Moving Development Environment to Containers with Podman

What Is Podman and Does It Work?


Podman is a replacement for Docker for local development of containerized applications. Podman commands map 1 to 1 to Docker commands, including their arguments. You could alias docker with podman and never notice that there is a completely different tool for managing your local containers.


One of the core features of Podman is its focus on security. There is no daemon involved in using Podman. It uses a traditional fork-exec model instead and also heavily utilizes user namespaces and network namespaces. As a result, Podman is a bit more isolated and in general more secure to use than Docker. You can even be root in a container without granting container or Podman any root privileges on the host — and user in a container won't be able to do any root-level tasks on the host machine.


A good example of how Podman's model can lead to better security is covered in an article, "Podman: A more secure way to run containers." If you want to learn more about how Podman leverages Linux namespaces, start with, "Podman and user namespaces: A marriage made in heaven" article. Finally, if you want to read about possible obstacles that you might have with this approach, then read, "The shortcomings of rootless containers."


For most of the users, the internals of Podman should not matter too much in a day-to-day use. What does matter is that Podman provides the same developer experience as Docker while doing things in a slightly more secure way in the background. Let's see if that's true.


Local Development Environment of mkdev.me


The main web application behind mkdev.me is written in Ruby on Rails. For a developer to be able to run this application locally he or she needs:


PostgreSQL server;


Redis server;


Mattermost instance (for our chat solution);


Mattermost test instance (to be used during automated tests);


In total, that's five services to run locally (including web application itself). One can imagine that for any new developer to install and configure all of it by hand can take quite some time. And once it's done, there is no guarantee that resulting local environment is close to the production one: a developer could install different PostgreSQL or Mattermost versions, that were not yet tested to work with mkdev.


Wouldn't it be great to bootstrap a complete development environment with one command and get a production-like setup running in seconds? That's what Docker and Docker Compose provided developers with. That's what Podman can provide as well.


Podman's Pods and What They Are Good For


On top of the regular containers, Podman has pods. If you ever heard of Kubernetes, this concept is familiar to you. In Kubernetes, a pod is the smallest deployment unit that consists of one or more containers. Podman's pods are exactly the same. All containers inside the pod share the same network namespace, so they can easily talk to each other over localhost without the need to export any extra ports.


There are three possible use cases for pods.


1. Prepare Your Application for Running on Kubernetes/Openshift

You could use pods in Podman as a preparation step before moving it to Kubernetes. In many cases, for real-world web applications, you probably will be better off using minikube, which will guarantee you the same APIs and functionality Kubernetes has. You would want to have Deployments, Services, and other resources, that would be a vital part of your setup in production. Just having a way to simulate pods with Podman won't be of much benefit for this.

2. Run Your Application with Podman in Production

You could decide that complete container orchestration is an overkill for you (and that would be a very good decision in many cases). Then it would make sense to still use containers for packaging and delivering your application. And in certain cases, you could benefit from not just running one container, but running multiple ones inside the pod on your production server. The question is what exactly will be the benefit of putting your containers inside the pod versus just running them as separate systemd managed services? I don't have a good answer here, but the feature is there and someone might find a use case for it in production.

3. Simplifying Your Development Environment

The final and the most attractive reason for developers is to use Podman pods to automate development environment. In this case, you would run all the services your application depends on inside the same pod. This is absolutely not something you should ever do in production environment on a real Kubernetes cluster, as your services should be running in different pods behind different replication controllers and service endpoints. But for local development doing it this way is convenient.

Podman Pods and Kubernetes Pods

Before we move to some real examples, we need to learn about one pod-related feature of Podman: play kube. Podman doesn't have a replacement to Docker Compose. There is a third-party tool podman-compose that might bring this functionality, but we at mkdev didn't get to test it yet.

Instead of Docker Compose, Podman has pods and a way to run them out of YAML definition. This YAML definition is compatible with Kubernetes pods YAML, meaning that you can take this YAML, load it into your Kubernetes cluster and expect some pods running.

Out of scope: Supporting docker-compose. We believe that Kubernetes is the defacto standard for composing Pods and for orchestrating containers, making Kubernetes YAML a defacto standard file format. - Podman documentation

You could use pods in Podman as a preparation step before moving it to Kubernetes. In many cases, for real-world web applications, you probably will be better off using minikube, which will guarantee you the same APIs and functionality Kubernetes has. You would want to have Deployments, Services, and other resources, that would be a vital part of your setup in production. Just having a way to simulate pods with Podman won't be of much benefit for this.

Basic Usage of Podman

We first need to create a new pod that will expose port 5432:

podman pod create --name postgresql -p 5432 -p 9187


We can see running pods with podman pod ps command:

POD ID NAME STATUS CREATED # OF CONTAINERS INFRA ID
235164dd4137 postgresql Created 26 seconds ago 1 229b2a70b8c4


When you create a new pod, Podman automatically starts infra container, which you can see by running podman ps.

Let's start a PostgreSQL container inside this pod:

podman run -d --pod postgresql -e POSTGRES_PASSWORD=password postgres:latest


If you don't have postgres:latest image yet, Podman will pull it automatically, from Docker Hub — the same experience you would have with Docker CLI.

Let's start another container inside postgresql pod: with a PostgreSQL Prometheus exporter:

podman run -d --pod postgresql -e DATA_SOURCE_NAME="postgresql://postgres:password@localhost:5432/postgres?sslmode=disable" wrouesnel/postgres_exporter


We can see top processes inside the pod with podman pod top postgresqlcommand. And we can access PostgreSQL metrics if we curl localhost:9187/metrics.

If we want to create the same setup again without running imperative shell commands and to store this setup as a declarative code, we can run podman generate kube postgresql > postgresql.yaml which will result in a Kubernetes-compatible pod definition. If you follow the link and examine this YAML file, you will see that Podman correctly configured all the ports and even exported all the environment variables, which you can cleanup if you want to rely on the image defaults.

Remove the pod with podman pod rm postgresql -f. Then, instead of running all of the commands again, simply run podman play kube postgresql.yaml to get the same result. You could also kubectl apply -f postgresql.yaml and get this PostgreSQL running on your Kubernetes cluster.

Warning: if you happen to use Podman 1.4.2, then at this point you will hit a bug described in this GitHub Issue. Let's hope by the time you read it the issue is fixed. If it's not fixed, then follow steps to fix your YAML from the Issue description or simply copy contents of my gist, which already contains a fixed definition.

The YAML file generated by Podman should not be used "as is," because Podman dumps all environment variables, securityContext and other things that you could leave without in your development environment and that might have better defaults in your Kubernetes cluster. Consider it a convenient scaffolding, not a final result.

Using Podman in a Real Ruby on Rails Application

At mkdev we completely automated our development environment with Podman. New developers (assuming they have a Linux machine running) can run a single script ./script/bootstrap.sh to get the application running. The script itself looks like this:

#!/bin/bash
set +e
if [ "$(podman pod ps | grep mkdev-dev | wc -l)" == "0" ] ; then
  echo "> > > Starting PostgreSQL, Redis and Mattermost"
  podman play kube pod.yaml
else
  echo "Development pod is already running. Re-create it? Y/N"
  read input
  if [ $input == "Y" ] ; then
    podman pod rm mkdev-dev -f
    podman play kube pod.yaml
  else
    echo "Leaving bootstrap process."
    exit 0
  fi
fi
echo "> > > Waiting for PostgreSQL to start"
until podman exec postgres psql -U postgres -c '\list'
do
  echo "> > > > > > PostgreSQL is not ready yet"
  sleep 1
done
podman exec -u postgres postgres psql -U postgres -d template1 -c 'create extension hstore;'
echo "> > > Creating development IM database"
until podman exec -u postgres postgres createdb mattermost; do sleep 1; done
echo "> > > Creating test IM database"
until podman exec -u postgres postgres createdb mattermost_test; do sleep 1; done
echo "> > > Creating and seeding the database"
./script/setup.sh
./script/exec.sh 'bundle exec rails db:create db:migrate db:test:prepare'
./script/seed.sh
echo "> > > Attempting to start the app"
./script/run.sh



Reference

Source -> https://dzone.com/articles/dockerless-part-3-moving-development-environment-t




Comments

Popular Posts