Podman

Podman is a powerful, open-source container management tool designed to simplify the deployment and management of containers and containerized applications. Unlike traditional container engines, Podman is daemonless, meaning it does not rely on a central service. This architecture provides enhanced security and flexibility, as it reduces the attack surface and eliminates the need for a root-level daemon. Podman also mirrors Docker’s command-line interface, allowing developers and system administrators to transition seamlessly between the two tools.

One of Podman’s standout features is its focus on modern orchestration needs. Built with Kubernetes in mind, Podman integrates sophisticated features that allow users to convert containers or pods directly into declarative Kubernetes manifests. Additionally, Podman supports rootless containers, enabling unprivileged users to manage containers securely without elevated permissions. Whether you’re building, running, or transitioning to orchestrated environments, Podman offers a lightweight, versatile, and robust solution tailored for contemporary DevOps workflows.

Demo

GO static page server

within an interactive Alpine container running on Podman:

podman run -d -i -t --name <name of container> -p 8080:8080 docker.io/library/golang:alpine

Note: These commands let one create, detach, attach, interactive with and expose a new container with a specified name, the individual components of this command go as such: -d Detached (runs in background) -i (Interactive Mode) -t(TTY Mode) --name example (name the container) -p (specify ports host:container) - 8080:8080 listen/broadcast on port 80 of the container (Differs from the internal network) - docker.io/library/golang:alpine

Step 1: Check up on the container

$ podman ps

Step 2: Attach to the container

$ podman attach <name>

$ apk add vim

Step 3: Create a project directory within the container

$ mkdir root/static/templates   

Step 4: Create an HTML file in templates

$ vim index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Landing Page</title>
        <script src="https://cdn.tailwindcss.com"></script>
    </head>
    <body class="bg-gray-100 flex items-center justify-center min-h-screen">
        <div class="text-center p-6 bg-white rounded-lg shadow-lg">
            <h1 class="text-4xl font-bold text-gray-800 mb-4">Welcome to the Served Index Page</h1>
            <p class="text-gray-600 text-lg mb-6">
                This page is being served to port 80 from a running container.
            </p>
            <p class="text-xl font-semibold text-gray-700 mb-8">
                Learn more
            </p>
            <div class="flex justify-center space-x-4">
                <a href="https://podman.io/" target="_blank" class="px-6 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition">
                    Podman Documentation
                </a>
                <a href="https://go.dev/" target="_blank" class="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition">
                    Go Website
                </a>
                <a href="https://www.w3.org/" target="_blank" class="px-6 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition">
                    W3C Website
                </a>
            </div>
        </div>
    </body>
    </html>


:wq

Step 6:

Move back up to the root of the project directory and create the go static page server file

$ cd ../..

in the project root directory

vim main.go

paste this:

    package main

    import (
        "html/template"
        "net/http"
        "log"
    )

    func main() {
        // Handle root route
        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
            tmpl, err := template.ParseFiles("static/templates/index.html")
            if err != nil {
                http.Error(w, err.Error(), http.StatusInternalServerError)
                return
            }
            tmpl.Execute(w, nil)
        })

        // Start server on port 8080
        log.Println("Server started at http://localhost:8080")
        log.Fatal(http.ListenAndServe(":8080", nil))
    }

:wq

Step 7: Run the go file from the root directory

go run main.go&

Step 8: Visit hosted site in browser

http://localhost:8080/

Step 9: Exit container without killing it

ctrl+p
ctrl+q

Lessons Learned:

  • There are two ways to connect to a container 1. Podman exec bash 2. Podman attach
  • Simple containers like the go Alpine image work on a single shell session
  • exiting a container with 'exit' will not end will as it will signal to the shell session SIGTERM, this took a while to figure out. Burried in the documentation, was a graceful way of exiting, leaving jobs intact (ctrl+p, ctrl+q), this mimics the behavior of

Tmux where one detaches from a session while leaving it running. This convention was introduced by Docker.


Creating a more sophisticated container with podman-compose:

mkdir cd

vim podman-compose.yml

version: '3.9'

services: : image: docker.io/library/golang:alpine # Fully qualified image name container_name: # Assign a custom container name stdin_open: true # Enable interactive mode (-i) tty: true # Enable TTY (-t) restart: unless-stopped command: > sh -c " apk update && apk add --no-cache vim tmux shadow git tree lf && echo 'syntax on' >> /root/.vimrc && echo 'set number' >> /root/.vimrc && echo 'set tabstop=4' >> /root/.vimrc && echo 'PS1="[\u@\h \W]\$ "' >> /root/.bashrc && echo 'alias ll="ls -lah"' >> /root/.bashrc && sh "

:wq

podman-compose up -d

podman ps

podman attach to <name> or PID

ctrl+p

ctrl+q