1"use strict";(self.webpackChunkfluvio_docs=self.webpackChunkfluvio_docs||[]).push([[2214],{15490:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>l,contentTitle:()=>c,default:()=>d,frontMatter:()=>r,metadata:()=>s,toc:()=>a});var t=o(74848),i=o(28453);const r={sidebar_position:900,title:"Docker: Custom App Container",description:"Packaging custom fluvio apps in a Docker environment"},c=void 0,s={id:"fluvio/installation/advanced/docker-custom-clients",title:"Docker: Custom App Container",description:"Packaging custom fluvio apps in a Docker environment",source:"@site/docs/fluvio/installation/advanced/docker-custom-clients.mdx",sourceDirName:"fluvio/installation/advanced",slug:"/fluvio/installation/advanced/docker-custom-clients",permalink:"/docs/latest/fluvio/installation/advanced/docker-custom-clients",draft:!1,unlisted:!1,editUrl:"https://github.com/infinyon/fluvio-docs/tree/main/docs/fluvio/installation/advanced/docker-custom-clients.mdx",tags:[],version:"current",lastUpdatedBy:"Felipe Cardozo",lastUpdatedAt:1752028303e3,sidebarPosition:900,frontMatter:{sidebar_position:900,title:"Docker: Custom App Container",description:"Packaging custom fluvio apps in a Docker environment"},sidebar:"fluvio",previous:{title:"Kubernetes",permalink:"/docs/latest/fluvio/installation/kubernetes"},next:{title:"Kubernetes: Helm & More",permalink:"/docs/latest/fluvio/installation/advanced/kubernetes-advanced"}},l={},a=[{value:"Example custom Fluvio client",id:"example-custom-fluvio-client",level:3},{value:"Example Dockerfile",id:"example-dockerfile",level:3},{value:"Running docker image",id:"running-docker-image",level:2},{value:"Run with <code>docker run</code>",id:"run-with-docker-run",level:3},{value:"Run with <code>docker compose</code> (alternative)",id:"run-with-docker-compose-alternative",level:3}];function u(e){const n={a:"a",code:"code",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(n.p,{children:["In this guide, you'll learn how to package your custom app with a Fluvio client into a Docker image, and how to run a container with ",(0,t.jsx)(n.code,{children:"docker"})," CLI."]}),"\n",(0,t.jsxs)(n.p,{children:["This tutorial assumes you have a fluvio cluster running. If you don't, follow the ",(0,t.jsx)(n.a,{href:"/docs/latest/fluvio/quickstart",children:"Quickstart"})," to get set up."]}),"\n",(0,t.jsx)(n.h3,{id:"example-custom-fluvio-client",children:"Example custom Fluvio client"}),"\n",(0,t.jsx)(n.p,{children:"To help illustrate the basic development workflow for all services using a Fluvio client, we'll create this sample Rust service."}),"\n",(0,t.jsx)(n.p,{children:"Run these commands to initialize the project"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",metastring:'copy="fl"',children:"$ cargo new fluvio-rust-client\n$ cd fluvio-rust-client\n$ cargo add async-std --features attributes\n$ cargo add chrono fluvio\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Copy this code into ",(0,t.jsx)(n.code,{children:"src/main.rs"})]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-rust",children:'use async_std::stream::StreamExt;\nuse chrono::Local;\nuse fluvio::metadata::topic::TopicSpec;\nuse fluvio::{Fluvio, RecordKey};\n\nconst TOPIC_NAME: &str = "hello-rust";\nconst PARTITION_NUM: u32 = 0;\nconst PARTITIONS: u32 = 1;\nconst REPLICAS: u32 = 1;\n\n/// This is an example of a basic Fluvio workflow in Rust\n///\n/// 1. Establish a connection to the Fluvio cluster\n/// 2. Create a topic to store data in\n/// 3. Create a producer and send some bytes\n/// 4. Create a consumer, and stream the data back\n#[async_std::main]\nasync fn main() {\n // Connect to Fluvio cluster\n let fluvio = Fluvio::connect().await.unwrap();\n\n // Create a topic\n let admin = fluvio.admin().await;\n let topic_spec = TopicSpec::new_computed(PARTITIONS, REPLICAS, None);\n let _topic_create = admin\n .create(TOPIC_NAME.to_string(), false, topic_spec)\n .await;\n\n // Create a record\n let record = format!("Hello World! - Time is {}", Local::now().to_rfc2822());\n\n // Produce to a topic\n let producer = fluvio::producer(TOPIC_NAME).await.unwrap();\n producer.send(RecordKey::NULL, record).await.unwrap();\n // Fluvio batches outgoing records by default, so flush producer to ensure all records are sent\n producer.flush().await.unwrap();
1\n\n // Consume last record from topic\n let consumer = fluvio::consumer(TOPIC_NAME, PARTITION_NUM).await.unwrap();\n let mut stream = consumer.stream(fluvio::Offset::from_end(1)).await.unwrap();\n if let Some(Ok(record)) = stream.next().await {\n let string = String::from_utf8_lossy(record.value());\n println!("{}", string);\n }\n}\n'})}),"\n",(0,t.jsx)(n.h3,{id:"example-dockerfile",children:"Example Dockerfile"}),"\n",(0,t.jsxs)(n.p,{children:["Save the following ",(0,t.jsx)(n.code,{children:"Dockerfile"}),". This Dockerfile adds our workflow an starts it with ",(0,t.jsx)(n.code,{children:"cargo run"}),", which will always build the code before it starts."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'FROM rust:1.73.0\n\n# Run as the `fluvio` user instead of root\nENV USER=fluvio\nRUN useradd --create-home "$USER"\nUSER $USER\nWORKDIR /home/fluvio\n\n# Copy your Rust project and run it\nCOPY --chown=$USER:$USER Cargo.toml .\nCOPY --chown=$USER:$USER src ./src\nCMD /usr/local/cargo/bin/cargo run\n'})}),"\n",(0,t.jsx)(n.h2,{id:"running-docker-image",children:"Running docker image"}),"\n",(0,t.jsxs)(n.p,{children:["The fluvio clients search for connection information from a config file located at ",(0,t.jsx)(n.code,{children:"$HOME/.fluvio/config"}),"."]}),"\n",(0,t.jsxs)(n.h3,{id:"run-with-docker-run",children:["Run with ",(0,t.jsx)(n.code,{children:"docker run"})]}),"\n",(0,t.jsxs)(n.p,{children:["In this example, we build our docker image with ",(0,t.jsx)(n.code,{children:"docker build"})," then start a container from the image with ",(0,t.jsx)(n.code,{children:"docker run"}),". We volume mount our host's config file to the container when we start."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell",children:"$ docker build -t fluvio-client-example .\n$ docker run -v $HOME/.fluvio/config:/home/fluvio/.fluvio/config --init --rm fluvio-client-example\n"})}),"\n",(0,t.jsx)(n.p,{children:"After running you'll see the following output:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"Running `target/debug/fluvio-rust-client`\nHello World! - Time is Tue, 10 Oct 2023 21:09:05 +0000\n"})}),"\n",(0,t.jsx)(n.p,{children:"The same event has been published to the topic:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"$ fluvio consume -Bd hello-rust\nConsuming records from 'hello-rust' starting from the beginning of log\nHello World! - Time is Tue, 10 Oct 2023 21:09:05 +0000\n"})}),"\n",(0,t.jsxs)(n.h3,{id:"run-with-docker-compose-alternative",children:["Run with ",(0,t.jsx)(n.code,{children:"docker compose"})," (alternative)"]}),"\n",(0,t.jsxs)(n.p,{children:["Copy this yaml file and save it as ",(0,t.jsx)(n.code,{children:"docker-compose.yaml"})]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-yaml",children:'# docker-compose.yaml\nversion: "3"\nservices:\n example:\n build: .\n volumes:\n - $HOME/.fluvio/config:/home/fluvio/.fluvio/config:ro\n'})}),"\n",(0,t.jsxs)(n.p,{children:["In this example, we build our docker image with ",(0,t.jsx)(n.code,{children:"docker compose build"})," then start a container from the image with ",(0,t.jsx)(n.code,{children:"docker compose up"}),". We volume mount our host's config file to the container when we start."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell",children:"$ docker compose build\n$ docker compose up\n"})})]})}function d(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(u,{...e})}):u(e)}},28453:(e,n,o)=>{o.d(n,{R:()=>c,x:()=>s});var t=o(96540);const i={},r=t.createContext(i);function c(e){const n=t.useContext(r);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function s(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:c(e.components),t.createElement(r.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.