Taking Docker Compose to Production with One Tool
Ajeet Singh Raina
?? Follow me for Docker, Kubernetes, Cloud-Native, LLM and GenAI stuffs | Technology Influencer | ?? Developer Advocate at Docker | Author at Collabnix.com | Distinguished Arm Ambassador
Imagine you're using Docker Compose to develop and test your app. It’s a great tool for getting multiple containers to work together on a single host, perfect for local development. But when it comes to production, especially if you need to scale or handle higher traffic, Kubernetes often makes more sense.
But why?
Kubernetes adds built-in support for load balancing, service discovery, and automatic failover, which are essential for managing complex, distributed applications in production.
That’s where tools like Compose Bridge come in. You can develop with Docker Compose and then convert your Compose files to Kubernetes resources when you’re ready to go live. This way, you’re not sacrificing the simplicity of Compose during development but still getting the power of Kubernetes when you need it in production. It’s a smooth way to bridge the gap between development and scalable production.
What is Compose Bridge?
Compose Bridge, an experimental feature in Docker Desktop, offers a powerful solution for transforming Docker Compose configurations into Kubernetes manifests, bridging the gap between local development and production-ready orchestration. This tool significantly simplifies the transition from Docker Compose to Kubernetes, allowing developers to leverage the simplicity of Compose while harnessing the scalability and robustness of Kubernetes deployments.
Understanding Compose Bridge
At its core, Compose Bridge operates by utilising transformations packaged as Docker images. These transformations receive a fully resolved Compose model as input (/in/compose.yaml) and produce target format files as output (/out). The default transformation provided by Compose Bridge focuses on generating Kubernetes manifests and a Kustomize overlay, specifically designed for deployment on Docker Desktop with Kubernetes enabled.
The transformation process leverages Go templates, which allows for easy customization and extension. This templating system enables developers to insert logic and data dynamically, making the generated Kubernetes manifests adaptable to various project requirements. The use of Go templates also provide access to a set of YAML helper functions, such as seconds for converting durations, uppercase for string manipulation, and base64 for encoding secrets.
Key Benefits
Key benefits of using Compose Bridge include:
While Compose Bridge offers significant advantages, it's important to note that as an experimental feature, it may undergo changes in future releases. Additionally, complex applications might still require manual adjustments to fully optimize for Kubernetes deployments. Despite these considerations, Compose Bridge represents a valuable tool in the Docker ecosystem, streamlining the containerization workflow from development to production.
How is it different from other conversion tools?
Great question.
Setting Up Compose Bridge
Prerequisites
Before setting up Compose Bridge, ensure:
Steps
After enabling the feature, Compose Bridge becomes available for use.
Overview of the Default Kubernetes Transformation
The default transformation simplifies initial migrations, converting Compose files to Kubernetes-ready configurations. This transformation is intended to quickly generate Kubernetes YAML manifests that map closely to the original Docker Compose settings.
How it works
Compose bridge uses transformations to let you convert a Compose model into another form. A transformation is packaged as a Docker image that receives the fully-resolved Compose model as /in/compose.yaml and can produce any target format file under /out. Compose Bridge provides its transformation for Kubernetes using Go templates, so that it is easy to extend for customization by just replacing or appending your own templates.
The default Compose Bridge transformation generates Kubernetes resources that include:
How to Use the Default Transformation
$ compose-bridge convert --help
$ compose-bridge convert --help
Usage: docker compose-bridge convert [OPTIONS]
Convert a Compose file to Kubernetes resources
Options:
-f, --file stringArray Compose configuration files
-o, --output string The output directory for the Kubernetes resources (default "out")
--templates string Directory containing transformation templates
-t, --transformation stringArray Transformation to apply to compose model (default:
docker/compose-bridge-kubernetes)
If you want to convert a compose.yaml file that is located in another directory, you can run:
compose-bridge convert -f <path-to-file>/compose.yaml
Learn more about the default transformation on the official Docker docs
Sample Application: From Compose to Kubernetes
We’ll use a basic example featuring a web server and database service for this demonstration.
Writing the Docker Compose File
Create a docker-compose.yml with the following configuration:
services:
web:
image: nginx
ports:
- "80:80"
db:
image: postgres
environment:
POSTGRES_PASSWORD: example
Using Compose Bridge to Transform the Compose File
Compose Bridge will convert docker-compose.yml into Kubernetes manifests and apply them.
compose-bridge convert
latest: Pulling from library/postgres
5ecbc93de950: Download complete
ba6e84deecdb: Download complete
425a818d8223: Download complete
159c4494c279: Download complete
b0dd2bf7a180: Download complete
f7fdac227b96: Download complete
3dc01759541c: Download complete
c0a40d31bfac: Download complete
90646cadd7e6: Download complete
e868621ffb41: Download complete
f6ce5b6f352e: Download complete
e1dbef7dcaa1: Download complete
6b732c95d024: Download complete
Digest: sha256:8d3be35b184e70d81e54cbcbd3df3c0b47f37d06482c0dd1c140db5dbcc6a808
Status: Downloaded newer image for postgres:latest
latest: Pulling from library/nginx
2c1384c86539: Download complete
51635e63ab0c: Download complete
805908969407: Download complete
b9a670e7a7f3: Download complete
6c29a458e7d5: Download complete
1f62b39dc401: Download complete
Digest: sha256:28402db69fec7c17e179ea87882667f1e054391138f77ffaf0c3eb388efc3ffb
Status: Downloaded newer image for nginx:latest
latest: Pulling from docker/compose-bridge-kubernetes
af80f65e8b88: Download complete
062101437435: Download complete
99d8bc75d872: Download complete
Digest: sha256:698ecbaaf8abf299cddcf1f9de08509858a9e9199cc6d2f19ba5bf650b72c334
Status: Downloaded newer image for docker/compose-bridge-kubernetes:latest
Kubernetes resource db-deployment.yaml created
Kubernetes resource web-deployment.yaml created
Kubernetes resource db-expose.yaml created
Kubernetes resource web-expose.yaml created
Kubernetes resource 0-10nov-namespace.yaml created
Kubernetes resource default-network-policy.yaml created
Kubernetes resource web-service.yaml created
Kubernetes resource kustomization.yaml created
Kubernetes resource web-service.yaml created
Kubernetes resource kustomization.yaml created
Analyzing the Generated Kubernetes Manifests
The above command creates manifests that represent each service as a Kubernetes pod. These files are then stored within your project in the /out folder.
tree out
out
├── base
│?? ├── 0-10nov-namespace.yaml
│?? ├── db-deployment.yaml
│?? ├── db-expose.yaml
│?? ├── default-network-policy.yaml
│?? ├── kustomization.yaml
│?? ├── web-deployment.yaml
│?? ├── web-expose.yaml
│?? └── web-service.yaml
└── overlays
└── desktop
├── kustomization.yaml
└── web-service.yaml
4 directories, 10 files
The Kubernetes manifests can then be used to run the application on Kubernetes using the standard deployment command kubectl apply -k out/overlays/desktop/.
kubectl apply -k out/overlays/desktop/
namespace/10nov created
service/db created
service/web created
service/web-published created
deployment.apps/db created
deployment.apps/web created
networkpolicy.networking.k8s.io/default-network-policy created
You can verify this by running the CLI too:
kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
10nov db-7c7d8ffc7f-c6k2p 1/1 Running 0 27s
10nov web-b7c76985f-bn5lc 1/1 Running 0 27s
kube-system coredns-7db6d8ff4d-5g8ph 1/1 Running 0 4m20s
kube-system coredns-7db6d8ff4d-vn95x 1/1 Running 0 4m20s
kube-system etcd-docker-desktop 1/1 Running 2 4m26s
kube-system kube-apiserver-docker-desktop 1/1 Running 2 4m21s
kube-system kube-controller-manager-docker-desktop 1/1 Running 2 4m17s
kube-system kube-proxy-bt6pf 1/1 Running 0 4m21s
kube-system kube-scheduler-docker-desktop 1/1 Running 2 4m19s
kube-system storage-provisioner 1/1 Running 0 4m18s
kube-system vpnkit-controller 1/1 Running 0 4m18s
Examining the YAML files
cd out/overlays/desktop/
cat kustomization.yaml
#! kustomization.yaml
# Generated code, do not edit
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- path: web-service.yaml
cat web-service.yaml
# check if there is at least one published port
#! web-service.yaml
# Generated code, do not edit
apiVersion: v1
kind: Service
metadata:
name: web-published
namespace: 10nov
spec:
type: LoadBalancer
Now you can access Nginx running inside a Pod by accessing the web browser:
You can verify if Postgres is running or not by examining it's logs:
Volumes:
kube-api-access-rb8zn:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 9h default-scheduler Successfully assigned 10nov/db-7c7d8ffc7f-c6k2p to docker-desktop
Normal Pulled 9h kubelet Container image "postgres" already present on machine
Normal Created 9h kubelet Created container db
Normal Started 9h kubelet Started container db
Normal SandboxChanged 21m kubelet Pod sandbox changed, it will be killed and re-created.
Normal Pulled 21m kubelet Container image "postgres" already present on machine
Normal Created 21m kubelet Created container db
Normal Started 21m kubelet Started container db
?? Follow me for Docker, Kubernetes, Cloud-Native, LLM and GenAI stuffs | Technology Influencer | ?? Developer Advocate at Docker | Author at Collabnix.com | Distinguished Arm Ambassador
2 周BTW, you can keep your eyes on https://docs.docker.com/compose/bridge/advanced-integration/
?? Follow me for Docker, Kubernetes, Cloud-Native, LLM and GenAI stuffs | Technology Influencer | ?? Developer Advocate at Docker | Author at Collabnix.com | Distinguished Arm Ambassador
2 周Sanjay Wadhwani Tauseef Ameen Thanks for your comments. Compose Bridge can also function as a?kubectl?plugin, allowing you to integrate its capabilities directly into your Kubernetes command-line operations. I agree with you both. It does make sense to include the Helm plugin by default due to its popularity. As this is just an experimental feature, you can expect support for Helm in the future release. But still, I will check with the internal engineering team and confirm. Stay tuned !!
Founder & CTO at Spundan, Automate, DevOps, Cloud, AI, ML, Data
2 周Ajeet Singh Raina It would always be better to use manifests from scratch? Helm is yet another tooling / templating to reuse the manifests. Kubernetes had https://kompose.io/ which did similar stuff. But still the usage of it is fairly less. No doubt, for a beginner, this could certainly help.
Java Developer | Changing the world one nanometer at a time @ASML
2 周Great article, Ajeet Singh Raina ! The Compose Bridge feature in Docker Desktop is definitely a valuable addition. I noticed that developers need to use the kubectl plugin for Kubernetes deployments. Wouldn’t it be beneficial to include a Helm plugin by default as well, given Helm’s widespread use as an industry-standard tool for simplifying deployments?