podman_logo Podman is an OCI Open Containers Initiative specification compatible container-engine part of RedHat Linux which can be used instead of the Docker runtime.

oci_image

Podman in contrast to Docker is daemonless: it interacts directly with the containers, image registry and storage through the runC container runtime process just by using the CLI (podman); you can even alias podman as

alias docker=podman

without any problem!

How to install Podman on MacOs

Note: this guide is tested on a Macbook Pro 2019 (Intel).

brew install podman

Then, install the VM for Podman

podman machine init

and start it

podman machine start

Now you can run your first container with Podman!

~ ❯ podman run -it ubuntu bash
root@33f2fbcb526e:/# ls
bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

Podman Pods

One thing that is new to the ones that come from Docker is the Pod concept: introduced by Kubernetes, Podman pods are similar to them.

In a Podman pod containers can run together

podman pod create --name my-backend
podman run --pod my-backend --name mariadb docker.io/library/mariadb:10.5.12
podman run --pod my-backend --name apache docker.io/library/nginx:latest

This command is similar to Docker Compose, it allows us to group a set of containers together and allow them to interact with each other over localhost, in fact they share namespace, network and security context.

YAML Generation

In Podman there is the command podman generate kube which allows us to generate a Kubernetes YAML for a pod or even directly for a container!

podman generate kube my-backend

# Generation of Kubernetes YAML is still under development!
#
# Save the output of this file and use kubectl create -f to import
# it into Kubernetes.
#
# Created with podman-3.3.1
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2021-09-26T06:43:27Z"
  labels:
    app: my-backend
  name: my-backend
spec:
  containers:
  - args:
    - nginx
    - -g
    - daemon off;
    command:
    - /docker-entrypoint.sh
    env:
    - name: PATH
      value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    - name: TERM
      value: xterm
    - name: container
      value: podman
    - name: NGINX_VERSION
      value: 1.21.3
    - name: NJS_VERSION
      value: 0.6.2
    - name: PKG_RELEASE
      value: 1~buster
    image: docker.io/library/nginx:latest
    name: apache
    resources: {}
    securityContext:
      allowPrivilegeEscalation: true
      capabilities:
        drop:
        - CAP_MKNOD
        - CAP_NET_RAW
        - CAP_AUDIT_WRITE
      privileged: false
      readOnlyRootFilesystem: false
      seLinuxOptions: {}
    workingDir: /
  - args:
    - mysqld
    command:
    - docker-entrypoint.sh
    env:
    - name: PATH
      value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    - name: TERM
      value: xterm
    - name: container
      value: podman
    - name: GOSU_VERSION
      value: "1.13"
    - name: MARIADB_MAJOR
      value: "10.5"
    - name: MARIADB_VERSION
      value: 1:10.5.12+maria~focal
    image: docker.io/library/mariadb:10.5.12
    name: mariadb
    resources: {}
    securityContext:
      allowPrivilegeEscalation: true
      capabilities:
        drop:
        - CAP_MKNOD
        - CAP_NET_RAW
        - CAP_AUDIT_WRITE
      privileged: false
      readOnlyRootFilesystem: false
      seLinuxOptions: {}
    volumeMounts:
    - mountPath: /var/lib/mysql
      name: 4ba20106e41fc12d9e76828e6ca59d8870b1d6798bb13920e7bdacf0d7896f14-pvc
    workingDir: /
  dnsConfig: {}
  restartPolicy: Never
  volumes:
  - name: 4ba20106e41fc12d9e76828e6ca59d8870b1d6798bb13920e7bdacf0d7896f14-pvc
    persistentVolumeClaim:
      claimName: 4ba20106e41fc12d9e76828e6ca59d8870b1d6798bb13920e7bdacf0d7896f14
status: {}

As you may see this YAML needs some cleanup such as volume section, env and the securityContext (watch out!).

Now that we have a YAML file we can even deploy it on Kubernetes or deploy it on… Podman!

The command podman play kube starts a pod by a definied YAML.

~ ❯ podman play kube ./my-backend.yaml
Pod:
15044460351d0bd2171c14d1eb118b383bd0c118044e449a9c479b07e5953208
Containers:
e360a6d4086235f75d4ef2817f992e826ea067af432f0ba86f4f871625d5d501
17d6994ca94f3f0f995a755af37466b995d6448aabab5ea82b62d6b5ad6a4f0b

Issues that I found

I found just one issue (for now) when running podman on my Macbook: when stopping and starting again the VM with podman machine start I got

ERRO[0000] cannot add network services: listen tcp :55837: bind: address already in use
panic: interface conversion: net.Conn is nil, not *net.UnixConn

goroutine 1 [running]:
github.com/containers/podman/v3/pkg/machine/qemu.(*MachineVM).Start(0xc000129550, {0x16, 0xc00059fd70}, {})
	pkg/machine/qemu/machine.go:282 +0x91c
github.com/containers/podman/v3/cmd/podman/machine.start(0x2481ba0, {0x24d18d0, 0x0, 0x0})
	cmd/podman/machine/start.go:62 +0x1de
github.com/spf13/cobra.(*Command).execute(0x2481ba0, {0xc0000301d0, 0x0, 0x0})
	vendor/github.com/spf13/cobra/command.go:856 +0x60e
github.com/spf13/cobra.(*Command).ExecuteC(0x248c820)
	vendor/github.com/spf13/cobra/command.go:974 +0x3bc
github.com/spf13/cobra.(*Command).Execute(...)
	vendor/github.com/spf13/cobra/command.go:902
github.com/spf13/cobra.(*Command).ExecuteContext(...)
	vendor/github.com/spf13/cobra/command.go:895
main.Execute()
	cmd/podman/root.go:90 +0xbe
main.main()
	cmd/podman/main.go:39 +0x74

Seemed like the process was still listening on 55837 port. In order to get rid of it just kill the process

sudo lsof -i -P | grep LISTEN
kill -9 <pid>

then finally start the vm

podman machine start

Conclusion

As we saw, we can easily transition to Podman from Docker and unlike Docker, it has different features that allow us to generate Kubernetes YAMLs starting from a pod/container definition help us to make the jump to Kubernetes.

In the next posts, I will show other peculiarities about Podman and how it install it on Windows.