Subscribe to the feed

The Docker Compose tool has been valuable for many people who have been working with containers. According to the documentation, Docker Compose describes itself as:

... a tool for defining and running multi-container applications. With Compose, you use a YAML file to configure your application's services. Then, with a single command, you create and start all the services from your configuration.

One challenge with Docker Compose is that the YAML file format only works with the Docker engine. While you can give it to other Docker users for local replication, they cannot use it with other container runtimes. That is, until now.

[ Related tutorial: Using Podman and Docker Compose ]

With Podman 3.0, the Docker Compose works with a Podman backend

The real power of Podman shines through by easily converting the containers based on Docker Compose to a Kubernetes YAML file. Like Docker Compose, Podman can use the Kubernetes YAML file to replicate the containers locally. More importantly, this allows Podman to have an orchestrated pod and service that can be run on many platforms, including Kubernetes/OpenShift or minikube.

This article explains the process of starting with a simple Compose file that runs WordPress using two containers. The source for this Compose file is published on GitHub in Docker's awesome-compose repository. Successful use of this file with Podman results in the WordPress initial setup screen appearing in a browser.

Note: At the time of this writing, we only support the docker-compose command running rootfully.

Start Podman's system service

To use Compose, the first step is to make sure that all the required packages are installed and then to set up the Podman (3.0 or greater) system service using systemd. After installing packages, enable and start the Podman systemd socket-activated service using the following command:

$ sudo systemctl enable --now podman.socket

Verify the service is running by hitting the ping endpoint. This step needs to be successful before proceeding further.

$ sudo curl -H "Content-Type: application/json" --unix-socket /var/run/docker.sock http://localhost/_ping
OK

You can now confidently run Compose knowing the RESTful API is working.

Run Compose

As mentioned earlier, the example will run a Compose file consisting of two containers to bring up a WordPress session. One container runs an Apache web service, and the other stores the data in a MySQL database. The two containers communicate via TCP/IP over a network dedicated to this Compose instance. To bring up the containers, run docker-compose up.

$ sudo docker-compose up -d
Creating network "wordpress-mysql_default" with the default driver
Creating volume "wordpress-mysql_db_data" with default driver
Pulling db (mysql:8.0.19)...
0c27e8e5fcfab7805cfed996b55e5e98f43fd7ee76e1516f20cba139c6a299c5: pulling image () from docker.io/library/mysql:8.0.19  
Pulling wordpress (wordpress:latest)...
0d35c2300ec845fda141ba012f7c6dccde8f0ae106b8f4bb0fcfced69380f851: pulling image () from docker.io/library/wordpress:latest  
Creating wordpress-mysql_db_1        ... done
Creating wordpress-mysql_wordpress_1 ... done

Use the podman ps command to verify that two containers have been created and are now running. No Docker daemon was necessary.

$ sudo podman ps
CONTAINER ID  IMAGE                               COMMAND               CREATED         STATUS             PORTS               NAMES
a089a40bb9ae  docker.io/library/mysql:8.0.19      --default-authent...  15 seconds ago  Up 15 seconds ago                      kind_hermann
510c028c273f  docker.io/library/wordpress:latest  apache2-foregroun...  15 seconds ago  Up 15 seconds ago  0.0.0.0:80->80/tcp  competent_kilby
$

Verify WordPress is running locally

The instructions for running WordPress indicate that it is working correctly and it can be accessed using the localhost and port 80.

WordPress setup running locally

Create the Kubernetes YAML

With a working instance of WordPress on the local machine, begin the process of replicating these containers on a Kubernetes platform. Podman can generate Kubernetes-based YAML from running containers.

[ You might also like to read: Start learning Kubernetes from your local machine ]

One pod or multiple pods?

There are two approaches for creating the YAML you will use in the Kubernetes environment: Either put two containers in a single pod with a service, or create two pods, with one container in each, and a service to expose the Apache front end. Determining which approach is best may require some trial and error.

One consideration that may dictate which approach to use is how the containers or pods will communicate. When Compose created these containers, it went through a series of steps to ensure that the two containers could communicate with each other using DNS names. In fact, Compose set up aliases on the containers that are recognized as DNS names when resolving containers by name. By putting the containers inside the same pod, there is no need for name resolution between them because they share a network namespace. Therefore, they can simply use localhost to communicate with each other.

Placing the containers in different Kubernetes pods gives better flexibility, but the containers will need to communicate with each other using some other mechanism.

Generate the YAML

You must know the container names or IDs to begin creating the Kubernetes YAML. Decide whether Podman should generate a service description for Kubernetes. In this case, expose the Apache front end so that it can interact with WordPress using the browser. Use the podman generate kube command to create YAML files.

$ sudo podman generate kube -s -f wordpress.yaml a089a40bb9ae 510c028c273f

The -s in the previous command signifies that Podman will generate service for this pod. The -f option allows us to save the generated YAML into a file. Otherwise, the output is sent to stdout, where it can be redirected to a file.

$ cat wordpress.yaml
# Save the output of this file and use kubectl create -f to import
# it into Kubernetes.
#
# Created with podman-3.0.0-dev
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2020-12-03T22:30:07Z"
  labels:
    app: kindhermann
  name: kindhermann
spec:
  containers:
  - command:
    - docker-entrypoint.sh
    - --default-authentication-plugin=mysql_native_password
    env:
    - name: PATH
      value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
   ...
    workingDir: /
  - command:
    - docker-entrypoint.sh
    - apache2-foreground
    env:
    - name: PATH
      value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
  ...
    - name: WORDPRESS_DB_HOST
      value: kindhermann
    - name: WORDPRESS_DB_PASSWORD
      value: db
    - name: APACHE_ENVVARS
      value: /etc/apache2/envvars
 ...
    image: docker.io/library/wordpress:latest
    name: competentkilby
    ports:
    - containerPort: 80
      hostPort: 80
      protocol: TCP
    resources: {}
    securityContext:
      allowPrivilegeEscalation: true
      capabilities:
        drop:
        - CAP_MKNOD
        - CAP_NET_RAW
      privileged: false
      readOnlyRootFilesystem: false
      seLinuxOptions: {}
    workingDir: /var/www/html
status: {}
---
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: "2020-12-03T22:30:07Z"
  labels:
    app: kindhermann
  name: kindhermann
spec:
  ports:
  - name: "80"
    nodePort: 30579
    port: 80
    protocol: TCP
    targetPort: 0
  selector:
    app: kindhermann
  type: NodePort
status:
  loadBalancer: {}

In order for the Apache container to communicate with the MySQL container, the author of the Compose file has opted to use an environment variable named WORDPRESS_DB_HOST to signify the hostname of the MySQL container. Before running this in a Kubernetes environment, change the value of WORDPRESS_DB_HOST to the MySQL container name (kindhermann in this example) or 127.0.0.1 (containers within the same pod can communicate with each other over localhost).

...
    - name: WORDPRESS_DB_HOST
      value: kindhermann OR 127.0.0.1
---

 


SideBar:

When Compose performs a build

In many Compose examples, the author chooses to build their container image. This is usually because they require additional packages or want to perform some level of customization in the image. When this occurs, there will be an additional new image in Podman's image store. Choosing to run the outputted Kubernetes YAML might fail because it references a container image that is only present in the local store.

To remedy this, use podman push to move these new images to either a global registry like quay.io or a Kubernetes-specific registry so that Kubernetes can pull these images. Ensure the image name in the resulting YAML file is the same as the image that was pushed.


Kubernetes

The next step in carrying this example forward and applying it to a Kubernetes environment will show how to run this example on both minikube and OpenShift. There is nothing specific in the YAML that prevents the pods from running in another Kubernetes environment, so it should theoretically work with other Kubernetes flavors.

This article assumes the existence of a minikube and/or OpenShift environment. It is out of scope for this article to document the setup of a minikube or OpenShift Kubernetes environment.

minikube

The first step to deploying on minikube is simply to create the pod.

$ minikube kubectl -- create -f wordpress.yaml
pod/kindhermann created
service/kindhermann created

After waiting a few seconds, check the status of the pod and containers. Depending on the speed and network bandwidth, the pod may already be available. Check the status of the pod using kubectl get pods.

$ minikube kubectl -- get pods
NAME          READY   STATUS    RESTARTS   AGE
kindhermann   2/2     Running   0          28

Now that both containers are ready, test the availability of the WordPress session. First, get the IP address of the pod in Kubernetes using kubectl.

$ minikube kubectl -- describe  pods | grep Node:
Node:         minikube/192.168.39.7

Point your browser of choice to the pod's IP address and see the WordPress setup screen.

Connected to the WordPress setup by IP

OpenShift

For this article, an OpenShift cluster is running on GCP.

Use the generated wordpress.yaml to create the pod and service. If using a vanilla Kubernetes environment, replace oc with kubectl in the following commands.

$ oc create -f wordpress.yaml  
pod/kindhermann created
service/kindhermann created

Wait a few seconds for the pod and service to come up. The kindhermann pod is in Running status with both containers up and running. The kindhermann service is also available with a cluster IP assigned to it.

$ oc get pods
NAME          READY   STATUS    RESTARTS   AGE
kindhermann   2/2     Running   0          39s
$ oc get services
NAME          TYPE           CLUSTER-IP       EXTERNAL-IP                            PORT(S)        AGE
kindhermann   NodePort       172.30.103.100   <none>                                 80:30579/TCP   45s
Kubernetes    ClusterIP      172.30.0.1       <none>                                 443/TCP        44m
openshift     ExternalName   <none>           Kubernetes.default.svc.cluster.local   <none>         36m

View the pod and service in the console.

View pods in the console View services in the console

To access the service from outside of the cluster, expose it, which will create a route.

$ oc expose svc/kindhermann
route.route.openshift.io/kindhermann exposed
$ oc/kubectl get routes
NAME          HOST/PORT                                                                          PATH   SERVICES      PORT   TERMINATION   WILDCARD
kindhermann   kindhermann-default.apps.ci-ln-d3gw292-f76d1.origin-ci-int-gce.dev.openshift.com          kindhermann   80                   None

Exposing the service created the host/port route shown above and access that endpoint. View the setup page of the WordPress application running in the OpenShift or Kubernetes cluster.

WordPress setup running in OpenShift

Examine the route in the console and directly access the endpoint from there as well.

View routes in the console

[ Get this free ebook: Managing your Kubernetes clusters for dummies. ]

Wrap up

As you can see, moving workload configurations from Docker Compose environments to Kubernetes is straightforward with Podman 3.0. Podman not only gives the flexibility of Docker Compose while developing applications, but it also makes the move to Kubernetes easier when applications are ready for the big leagues. It does all this by using the podman generate kube command. Try it out yourself in three simple steps.


About the authors

Brent Baude has been working in hardware and software engineering for 27 years as an employee of IBM and Red Hat. Of late, he has specialized in Containers. His current role is that of Podman Architect.

Read full bio
UI_Icon-Red_Hat-Close-A-Black-RGB

Browse by channel

automation icon

Automation

The latest on IT automation for tech, teams, and environments

AI icon

Artificial intelligence

Updates on the platforms that free customers to run AI workloads anywhere

open hybrid cloud icon

Open hybrid cloud

Explore how we build a more flexible future with hybrid cloud

security icon

Security

The latest on how we reduce risks across environments and technologies

edge icon

Edge computing

Updates on the platforms that simplify operations at the edge

Infrastructure icon

Infrastructure

The latest on the world’s leading enterprise Linux platform

application development icon

Applications

Inside our solutions to the toughest application challenges

Original series icon

Original shows

Entertaining stories from the makers and leaders in enterprise tech