
Kompose is a great tool, billed as the meeting ground of Docker Compose and Kubernetes (Kubernetes + Compose = Kompose). In this article we will give a brief overview of using Kompose to move workloads from Docker Compose to Kubernetes.
Docker to Kubernetes with Kompose
You can download Kompose from their official site or their github page.
To get started, let’s use a simple Docker compose file for an echo service. This is a simple container that echo bad the request information, for example the requested path and headers.
version: "3"
services:
echo-server:
image: gcr.io/kubernetes-e2e-test-images/echoserver:2.2
ports:
- 32000:8080
Run this container to make sure we get the desired results.
$ docker compose -f docker-compse.yaml up -d
Now, curl to your host over port 32000 to confirm it is working.
$ curl http://localhost:32000
Hostname: 45e6784e1cc5
Pod Information:
-no pod information available-
Server values:
server_version=nginx: 1.12.2 - lua: 10010
Request Information:
client_address=172.27.0.1
method=GET
real path=/
query=
request_version=1.1
request_scheme=http
request_uri=http://localhost:8080/
Request Headers:
accept=*/*
host=localhost:32000
user-agent=curl/7.64.1
Request Body:
-no body in request-
Time to convert this to a set of Kubernetes manifests. Running with the convert subcommand and no parameters will pick up your docker-compose.yaml.
$ kompose convert
INFO Kubernetes file "echo-server-service.yaml" created
INFO Kubernetes file "echo-server-deployment.yaml" created
You will now notice two new files got created in your folder, echo-server-service.yaml & echo-server-deployment.yaml.
echo-server-service.yaml translates the services.echo-server.ports from our compose to a Kubernetes service exposing the ports. echo-server-deployment.yaml translates the container information to pods wrapped in a deployment.
Compose:
ports:– 32000:8080
Manifest
apiVersion: v1
kind: Service
metadata:
labels:
io.kompose.service: echo-server
name: echo-server
spec:
ports:
- name: "32000"
port: 32000
targetPort: 8080
selector:
io.kompose.service: echo-server
status:
loadBalancer: {}
Keep in mind, this defaults to exposing your service as a ClusterIP so it will only work inside your cluster. Addressing this will be part of our clean up efforts after converting it. We will see a bit later some changes that can be made ahead of time to the compose to affect this as well
Now for our container definition, in the compose we simply defined the image.
Compose:
image: gcr.io/kubernetes-e2e-test-images/echoserver:2.2
Once we convert this however it is wrapped in a Kubernetes deployment.
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
kompose.cmd: kompose convert
kompose.version: 1.23.0 (bc7d9f4f)
creationTimestamp: null
labels:
io.kompose.service: echo-server
name: echo-server
spec:
replicas: 1
selector:
matchLabels:
io.kompose.service: echo-server
strategy: {}
template:
metadata:
annotations:
kompose.cmd: kompose convert
kompose.version: 1.23.0 (bc7d9f4f)
creationTimestamp: null
labels:
io.kompose.service: echo-server
spec:
containers:
- image: gcr.io/kubernetes-e2e-test-images/echoserver:2.2
name: echo-server
ports:
- containerPort: 8080
resources: {}
restartPolicy: Always
status: {}
Without making any modifications at the moment, we are free to create these objects in Kubernetes. What we end up with is a Kubernetes Deployment running a single replica of the Echo container exposed as a ClusterIP address.
$ kubectl create -f echo-server-deployment.yaml -f echo-server-service.yaml
deployment.apps/echo-server created
service/echo-server created
Nice and easy, we have now moved a simple compose file to Kubernetes. But what if you wanted to expose that Kubernetes service as a NodePort instead of the default ClusterIP? Kompose supports about 15 custom labels that can control the output. Simply add the labels to your compose file, in this example we will add kompose.service.type and kompose.service.nodeport.port to our docker-compose.yaml.
version: "3"
services:
echo-server:
image: gcr.io/kubernetes-e2e-test-images/echoserver:2.2
ports:
- 32000:8080
labels:
kompose.service.type: nodeport
kompose.service.nodeport.port: "32087"
If you run kompose convert again, it will resulted in the updated manifest:
apiVersion: v1
kind: Service
metadata:
annotations:
kompose.cmd: kompose convert
kompose.service.nodeport.port: "32087"
kompose.service.type: nodeport
kompose.version: 1.23.0 (bc7d9f4f)
creationTimestamp: null
labels:
io.kompose.service: echo-server
name: echo-server
spec:
ports:
- name: "32000"
nodePort: 32087
port: 32000
targetPort: 8080
selector:
io.kompose.service: echo-server
type: NodePort
status:
loadBalancer: {}
The Kompose labels provide a bit more flexibility in defining the generated resources’ behavior upon conversion. They can be used on define healthchecks (readiness/liveness probes), pull secrets, services, volumes, etc.
As you can see, Kompose adds a fair amount of annotations to the converted files, but the majority of these can easily be removed by passing the the parmeter “–with-kompose-annotation=false”
kompose convert --with-kompose-annotation=false
One final comment, you may notice that if your docker-compose has a restart policy if “on-failure” it will convert to a Kuberentes Pod as opposed to a deployment. You could change the restart policy to “always” instead, but it can also be override through the controller command line parameter.
kompose convert --controller deployment
This parameter supports values of deployment, daemonSet and replicationController. That’s it for this post, hopefully it provided a good overview of the power of Kompose.