{"id":7416,"date":"2023-07-25T14:34:05","date_gmt":"2023-07-25T12:34:05","guid":{"rendered":"https:\/\/www.it-ps.at\/?p=7416"},"modified":"2024-10-16T11:05:45","modified_gmt":"2024-10-16T09:05:45","slug":"rootless-podman-docker","status":"publish","type":"post","link":"https:\/\/www.it-ps.at\/en\/rootless-podman-docker\/","title":{"rendered":"Using rootless Podman with Docker Compose"},"content":{"rendered":"\n<p>Podman is a nice tool, that simplifies running rootless containers without the need for a separate, rootful daemon. One of the tools that you might miss when migrating from Docker to Podman is Docker Compose, which provides an easy-to-use, declarative approach to running and orchestrating containers.<\/p>\n\n\n\n<p>Since the Podman API is compatible with the Docker API, we can use Docker Compose with Podman, with the Podman API simply pretending to be the Docker API when called by Docker Compose. This post shows you how you can get started.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Host setup<\/h2>\n\n\n\n<p>On the host, you need three things: Podman, Docker Compose, and a non-root user. Everything else we need for running this example can be found in the Github repository <a href=\"https:\/\/github.com\/clemens-zauchner\/podman-with-docker-compose\" target=\"_blank\" rel=\"noopener\" title=\"\">https:\/\/github.com\/clemens-zauchner\/podman-with-docker-compose<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Prerequisites<\/h3>\n\n\n\n<p>In this post it is assumed that you have a system user set up already, Podman installed and Docker NOT installed. It is recommended to use a Podman version 4, which ships with RHEL. Furthermore, the code snippets below are assumed to be run as the non-root (system) user.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Installing Docker Compose<\/h3>\n\n\n\n<p>You can download the latest version of Docker Compose directly from Github. In this case, we will simply save the binary in the home directory of the non-root user and run it from there. (If the directory <em>$HOME\/bin<\/em> does not exist, create it or modify the code below with a directory of your choice.)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>wget https:\/\/github.com\/docker\/compose\/releases\/latest\/download\/docker-compose-linux-$(uname -m) -O $HOME\/bin\/docker-compose\n\n$HOME\/bin\/docker-compose\nchmod +x $HOME\/bin\/docker-compose\nexport PATH=\"\/home\/$USER\/bin:$PATH\"<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Starting the Podman API socket<\/h3>\n\n\n\n<p><strong>Note<\/strong>: if you are using a system account, you need to export the&nbsp;<em>XDG_RUNTIME_DIR<\/em>&nbsp;to prevent the error <em>Failed to connect to bus: No medium found<\/em> in the next step.<em><br><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export XDG_RUNTIME_DIR=\"\/run\/user\/$(id -u)\"<\/code><\/pre>\n\n\n\n<p>You can start the rootless Podman API socket via a predefined systemd service using:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl --user start podman.socket<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Setting the DOCKER_HOST<\/h3>\n\n\n\n<p>You need to tell Docker Compose where to find the socket, so it can make API calls.<br>If you skip this step (and don&#8217;t have Docker installed, as we assume), you will get an error like this:<\/p>\n\n\n\n<p><em>Cannot connect to the Docker daemon at unix:\/\/\/var\/run\/docker.sock. Is the docker daemon running?<\/em><\/p>\n\n\n\n<p>You can fix it by setting the&nbsp;DOCKER_HOST&nbsp;environment variable:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export DOCKER_HOST=\"unix:\/\/\/run\/user\/$(id -u)\/podman\/podman.sock\"<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">The example application<\/h2>\n\n\n\n<p>Now let&#8217;s have a closer look at the files in our <a href=\"https:\/\/github.com\/clemens-zauchner\/podman-with-docker-compose\" target=\"_blank\" rel=\"noopener\" title=\"\">example repository<\/a>. (If you haven&#8217;t already cloned the repo and you want to follow along, do it now.)<\/p>\n\n\n\n<p>The declarations that Docker Compose interprets can be found in <em><a href=\"https:\/\/github.com\/clemens-zauchner\/podman-with-docker-compose\/blob\/main\/docker-compose.yml\" target=\"_blank\" rel=\"noopener\" title=\"\">docker-compose.xml<\/a><\/em>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>version: \"3\"\nservices:\n  flask:\n    build: .\n    ports:\n      - 5000:5000<\/code><\/pre>\n\n\n\n<p>We specify one service, called &#8220;flask&#8221;. For the corresponding container image, the build context is the current directory (&#8220;.&#8221;). We also specify to expose the port 5000 on the host, so we can reach the service from the host via <em>curl<\/em> (once the container image has been built and the container is up and running).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Building the image<\/h3>\n\n\n\n<p>You can build the image using&nbsp;<em>docker-compose build<\/em>. The build tool for Podman is usually&nbsp;<a href=\"https:\/\/buildah.io\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Buildah<\/a>, but if you use Docker Compose, a <a href=\"https:\/\/docs.docker.com\/build\/buildkit\/\" target=\"_blank\" rel=\"noopener\" title=\"\">BuildKit<\/a> container is started (however, via the Podman socket, i.e. with Podman as container engine!) and builds the image, as declared in the <a href=\"https:\/\/github.com\/clemens-zauchner\/podman-with-docker-compose\/blob\/main\/Dockerfile\" target=\"_blank\" rel=\"noopener\" title=\"\">Dockerfile<\/a> of our repository.<\/p>\n\n\n\n<p>When you look at the output of&nbsp;<em>podman ps<\/em> right after starting the build process, you can see a container&nbsp;<em>buildx_buildkit_default<\/em>&nbsp;running. This is the container that builds the image.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Starting and stopping the containers<\/h3>\n\n\n\n<p>To create and start the container (using the image that just has been built), you can use&nbsp;<em>docker-compose up<\/em>. This command will create a network and start the flask container. The code that runs within the container is a very simple web application defined <a href=\"https:\/\/github.com\/clemens-zauchner\/podman-with-docker-compose\/blob\/main\/flask\/app.py\" target=\"_blank\" rel=\"noopener\" title=\"\">here<\/a>. You can verify that everything works as expected using&nbsp;<em>curl<\/em>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>curl localhost:5000 &amp;&amp; echo\nHello from Flask!<\/code><\/pre>\n\n\n\n<p>To stop the containers, you can <em>use&nbsp;docker-compose down<\/em>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Drawbacks<\/h2>\n\n\n\n<p>Podman has some features, that are not supported by Docker Compose, e.g. pods or secrets. Although you can define secrets in the&nbsp;<em>docker-compose.yml<\/em>, this is only supported in swarm mode:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>version: \"3\"\nservices:\n  flask:\n    build: .\n    ports:\n      - 5000:5000\n    secrets:\n      - my_secret\n\nsecrets:\n  my_secret:\n    external: true<\/code><\/pre>\n\n\n\n<p>If you try that, you will get an error message <em>unsupported external secret mysecret.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>Podman really does play nicely with Docker Compose. For simple applications or local development, it is certainly an alternative. However, if you want to or need to use more advanced features, you will soon be limited by the features of Docker and Docker Compose.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Did you ever try to combine podman with docker compose? <\/p>\n","protected":false},"author":5,"featured_media":7419,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_EventAllDay":false,"_EventTimezone":"","_EventStartDate":"","_EventEndDate":"","_EventStartDateUTC":"","_EventEndDateUTC":"","_EventShowMap":false,"_EventShowMapLink":false,"_EventURL":"","_EventCost":"","_EventCostDescription":"","_EventCurrencySymbol":"","_EventCurrencyCode":"","_EventCurrencyPosition":"","_EventDateTimeSeparator":"","_EventTimeRangeSeparator":"","_EventOrganizerID":[],"_EventVenueID":[],"_OrganizerEmail":"","_OrganizerPhone":"","_OrganizerWebsite":"","_VenueAddress":"","_VenueCity":"","_VenueCountry":"","_VenueProvince":"","_VenueState":"","_VenueZip":"","_VenuePhone":"","_VenueURL":"","_VenueStateProvince":"","_VenueLat":"","_VenueLng":"","_VenueShowMap":false,"_VenueShowMapLink":false,"footnotes":""},"categories":[28],"tags":[],"class_list":["post-7416","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-data-ai"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.it-ps.at\/en\/wp-json\/wp\/v2\/posts\/7416","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.it-ps.at\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.it-ps.at\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.it-ps.at\/en\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/www.it-ps.at\/en\/wp-json\/wp\/v2\/comments?post=7416"}],"version-history":[{"count":1,"href":"https:\/\/www.it-ps.at\/en\/wp-json\/wp\/v2\/posts\/7416\/revisions"}],"predecessor-version":[{"id":9844,"href":"https:\/\/www.it-ps.at\/en\/wp-json\/wp\/v2\/posts\/7416\/revisions\/9844"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.it-ps.at\/en\/wp-json\/wp\/v2\/media\/7419"}],"wp:attachment":[{"href":"https:\/\/www.it-ps.at\/en\/wp-json\/wp\/v2\/media?parent=7416"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.it-ps.at\/en\/wp-json\/wp\/v2\/categories?post=7416"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.it-ps.at\/en\/wp-json\/wp\/v2\/tags?post=7416"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}