Ansible Pilot

Deploy Apache Web Server in a Podman Container for RedHat-like systems - Ansible modules podman_image and podman_container

How to automate the setup of a detached Apache httpd Web Server tag:latest in a Podman Container pass-throw of port 8080 to 80 and a custom index.html page for RedHat-like systems.

March 24, 2022
Access the Complete Video Course and Learn Quick Ansible by 200+ Practical Lessons

How to Setup Apache Web Server in a Podman Container for RedHat-like systems with Ansible?

I’m going to show you a live demo with some simple Ansible code. I’m Luca Berton and welcome to today’s episode of Ansible Pilot.

Setup Apache Web Server in a Podman Container for RedHat-like systems

Today we’re talking about how to Deploy a web server apache httpd in a Podman Container for RedHat-like Linux systems. The full process requires four steps that you could automate with different Ansible modules. Firstly you need to verify that podman and it dependency is successfully installed on the target system using the ansible.builtin.yum Ansible module. Secondly, you need to create the custom index.html with ansible.builtin.copy Ansible module. You could upgrade this step using the template module. Thirdly, you need to pull the image for the container hub registry using the containers.podman.podman_image Ansible module. Finally, you could run the webserver container setting the right port and settings using the containers.podman.podman_container Ansible module.

The Best Resources For Ansible

Video Course

Books

demo

How to Setup Apache Web Server in a Podman Container for RedHat-like systems with Ansible Playbook.

code

---
- name: deploy httpd container
  hosts: all
  become: true
  gather_facts: false
  vars:
    webroot: "/webroot"
  tasks:
    - name: podman installed
      ansible.builtin.yum:
        name: podman
        state: latest

    - name: pull image
      containers.podman.podman_image:
        name: httpd
        pull: true
        tag: latest

    - name: webroot present
      ansible.builtin.file:
        path: "{{ webroot }}"
        state: directory
        owner: "root"
        group: "root"
        mode: '0777'
        setype: "container_share_t"

    - name: custom index.html
      ansible.builtin.copy:
        dest: "{{ webroot }}/index.html"
        content: |
                    Custom Web Page
        setype: "container_share_t"

    - name: run httpd container
      containers.podman.podman_container:
        name: webserver
        image: httpd
        state: started
        detach: true
        expose:
          - 80
        ports:
          - 8080:80
        volume:
          - "{{ webroot }}:/usr/local/apache2/htdocs/:exec"

execution

ansible-pilot $ ansible-playbook -i virtualmachines/demo/inventory container/podman_httpd_redhat2.yml

PLAY [deploy httpd on container] ******************************************************************

TASK [podman installed] ***************************************************************************
changed: [demo.example.com]

TASK [pull image] *********************************************************************************
changed: [demo.example.com]

TASK [webroot present] ****************************************************************************
changed: [demo.example.com]

TASK [custom index.html] **************************************************************************
changed: [demo.example.com]

TASK [run httpd container] ************************************************************************
changed: [demo.example.com]

PLAY RECAP ****************************************************************************************
demo.example.com           : ok=5    changed=5    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

ansible-pilot $

idempotency

ansible-pilot $ ansible-playbook -i virtualmachines/demo/inventory container/podman_httpd_redhat2.yml

PLAY [deploy httpd on container] ******************************************************************

TASK [podman installed] ***************************************************************************
ok: [demo.example.com]

TASK [pull image] *********************************************************************************
ok: [demo.example.com]

TASK [webroot present] ****************************************************************************
changed: [demo.example.com]

TASK [custom index.html] **************************************************************************
ok: [demo.example.com]

TASK [run httpd container] ************************************************************************
changed: [demo.example.com]

PLAY RECAP ****************************************************************************************
demo.example.com           : ok=5    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

ansible-pilot $

before execution

ansible-pilot $ ssh [email protected]
Last login: Thu Mar 10 13:26:52 2022 from 192.168.0.59
[[email protected] ~]$ cat /etc/os-release 
NAME="Red Hat Enterprise Linux"
VERSION="8.5 (Ootpa)"
ID="rhel"
ID_LIKE="fedora"
VERSION_ID="8.5"
PLATFORM_ID="platform:el8"
PRETTY_NAME="Red Hat Enterprise Linux 8.5 (Ootpa)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:redhat:enterprise_linux:8::baseos"
HOME_URL="https://www.redhat.com/"
DOCUMENTATION_URL="https://access.redhat.com/documentation/red_hat_enterprise_linux/8/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 8"
REDHAT_BUGZILLA_PRODUCT_VERSION=8.5
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="8.5"
[[email protected] ~]$ podman images
-bash: podman: command not found
[[email protected] ~]$ podman ps -a
-bash: podman: command not found
[[email protected] ~]$ dnf info podman
Not root, Subscription Management repositories not updated
This system is not registered with an entitlement server. You can use subscription-manager to register.
Extra Packages for Enterprise Linux 8 - x86_64                     4.0 MB/s |  11 MB     00:02    
Extra Packages for Enterprise Linux Modular 8 - x86_64             1.1 MB/s | 979 kB     00:00    
Red Hat Enterprise Linux 8 for x86_64 - AppStream (RPMs)           5.2 MB/s |  39 MB     00:07    
Red Hat Enterprise Linux 8 for x86_64 - BaseOS (RPMs)              5.1 MB/s |  43 MB     00:08    
Last metadata expiration check: 0:00:01 ago on Thu 10 Mar 2022 01:49:01 PM UTC.
Available Packages
Name         : podman
Epoch        : 1
Version      : 3.4.2
Release      : 9.module+el8.5.0+13852+150547f7
Architecture : x86_64
Size         : 12 M
Source       : podman-3.4.2-9.module+el8.5.0+13852+150547f7.src.rpm
Repository   : rhel-8-for-x86_64-appstream-rpms
Summary      : Manage Pods, Containers and Container Images
URL          : https://podman.io/
License      : ASL 2.0 and GPLv3+
Description  : podman (Pod Manager) is a fully featured container engine that is a simple
             : daemonless tool.  podman provides a Docker-CLI comparable command line that
             : eases the transition from other container engines and allows the management of
             : pods, containers and images.  Simply put: alias docker=podman.
             : Most podman commands can be run as a regular user, without requiring
             : additional privileges.
             : 
             : podman uses Buildah(1) internally to create container images.
             : Both tools share image (not container) storage, hence each can use or
             : manipulate images (but not containers) created by the other.
             : 
             : Manage Pods, Containers and Container Images
             : podman Simple management tool for pods, containers and images
[[email protected] ~]$

after execution

ansible-pilot $ ssh [email protected]
Last login: Thu Mar 24 17:39:48 2022 from 192.168.0.59
[[email protected] ~]$ sudo su
[[email protected] devops]# cat /etc/os-release 
NAME="Red Hat Enterprise Linux"
VERSION="8.5 (Ootpa)"
ID="rhel"
ID_LIKE="fedora"
VERSION_ID="8.5"
PLATFORM_ID="platform:el8"
PRETTY_NAME="Red Hat Enterprise Linux 8.5 (Ootpa)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:redhat:enterprise_linux:8::baseos"
HOME_URL="https://www.redhat.com/"
DOCUMENTATION_URL="https://access.redhat.com/documentation/red_hat_enterprise_linux/8/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"

REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 8"
REDHAT_BUGZILLA_PRODUCT_VERSION=8.5
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="8.5"
[[email protected] devops]# podman images
REPOSITORY               TAG         IMAGE ID      CREATED     SIZE
docker.io/library/httpd  latest      b9bd7e513e0f  7 days ago  148 MB
[[email protected] devops]# podman ps -a
CONTAINER ID  IMAGE                           COMMAND           CREATED         STATUS             PORTS                 NAMES
804debe95694  docker.io/library/httpd:latest  httpd-foreground  58 seconds ago  Up 58 seconds ago  0.0.0.0:8080->80/tcp  webserver
[[email protected] devops]# dnf info podman
Updating Subscription Management repositories.
Last metadata expiration check: 0:12:45 ago on Thu 24 Mar 2022 05:28:22 PM UTC.
Installed Packages
Name         : podman
Epoch        : 1
Version      : 3.4.2
Release      : 9.module+el8.5.0+13852+150547f7
Architecture : x86_64
Size         : 48 M
Source       : podman-3.4.2-9.module+el8.5.0+13852+150547f7.src.rpm
Repository   : @System
From repo    : rhel-8-for-x86_64-appstream-rpms
Summary      : Manage Pods, Containers and Container Images
URL          : https://podman.io/
License      : ASL 2.0 and GPLv3+
Description  : podman (Pod Manager) is a fully featured container engine that is a simple
             : daemonless tool.  podman provides a Docker-CLI comparable command line that
             : eases the transition from other container engines and allows the management of
             : pods, containers and images.  Simply put: alias docker=podman.
             : Most podman commands can be run as a regular user, without requiring
             : additional privileges.
             : 
             : podman uses Buildah(1) internally to create container images.
             : Both tools share image (not container) storage, hence each can use or
             : manipulate images (but not containers) created by the other.
             : 
             : Manage Pods, Containers and Container Images
             : podman Simple management tool for pods, containers and images

[[email protected] devops]# podman inspect webserver
[
    {
        "Id": "804debe95694391a50b4e597cda2cbe7d5e88bc89da9efaf2325c871fc3c1688",
        "Created": "2022-03-24T17:39:49.78841153Z",
        "Path": "httpd-foreground",
        "Args": [
            "httpd-foreground"
        ],
        "State": {
            "OciVersion": "1.0.2-dev",
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 5066,
            "ConmonPid": 5057,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2022-03-24T17:39:50.278583744Z",
            "FinishedAt": "0001-01-01T00:00:00Z",
            "Healthcheck": {
                "Status": "",
                "FailingStreak": 0,
                "Log": null
            }
        },
        "Image": "b9bd7e513e0fc49bd6703bde67cf6526033a9bade13a34b7be04e0e7339f6d2e",
        "ImageName": "docker.io/library/httpd:latest",
        "Rootfs": "",
        "Pod": "",
        "ResolvConfPath": "/run/containers/storage/overlay-containers/804debe95694391a50b4e597cda2cbe7d5e88bc89da9efaf2325c871fc3c1688/userdata/resolv.conf",
        "HostnamePath": "/run/containers/storage/overlay-containers/804debe95694391a50b4e597cda2cbe7d5e88bc89da9efaf2325c871fc3c1688/userdata/hostname",
        "HostsPath": "/run/containers/storage/overlay-containers/804debe95694391a50b4e597cda2cbe7d5e88bc89da9efaf2325c871fc3c1688/userdata/hosts",
        "StaticDir": "/var/lib/containers/storage/overlay-containers/804debe95694391a50b4e597cda2cbe7d5e88bc89da9efaf2325c871fc3c1688/userdata",
        "OCIConfigPath": "/var/lib/containers/storage/overlay-containers/804debe95694391a50b4e597cda2cbe7d5e88bc89da9efaf2325c871fc3c1688/userdata/config.json",
        "OCIRuntime": "runc",
        "ConmonPidFile": "/run/containers/storage/overlay-containers/804debe95694391a50b4e597cda2cbe7d5e88bc89da9efaf2325c871fc3c1688/userdata/conmon.pid",
        "PidFile": "/run/containers/storage/overlay-containers/804debe95694391a50b4e597cda2cbe7d5e88bc89da9efaf2325c871fc3c1688/userdata/pidfile",
        "Name": "webserver",
        "RestartCount": 0,
        "Driver": "overlay",
        "MountLabel": "system_u:object_r:container_file_t:s0:c305,c750",
        "ProcessLabel": "system_u:system_r:container_t:s0:c305,c750",
        "AppArmorProfile": "",
        "EffectiveCaps": [
            "CAP_CHOWN",
            "CAP_DAC_OVERRIDE",
            "CAP_FOWNER",
            "CAP_FSETID",
            "CAP_KILL",
            "CAP_NET_BIND_SERVICE",
            "CAP_NET_RAW",
            "CAP_SETFCAP",
            "CAP_SETGID",
            "CAP_SETPCAP",
            "CAP_SETUID",
            "CAP_SYS_CHROOT"
        ],
        "BoundingCaps": [
            "CAP_CHOWN",
            "CAP_DAC_OVERRIDE",
            "CAP_FOWNER",
            "CAP_FSETID",
            "CAP_KILL",
            "CAP_NET_BIND_SERVICE",
            "CAP_NET_RAW",
            "CAP_SETFCAP",
            "CAP_SETGID",
            "CAP_SETPCAP",
            "CAP_SETUID",
            "CAP_SYS_CHROOT"
        ],
        "ExecIDs": [],
        "GraphDriver": {
            "Name": "overlay",
            "Data": {
                "LowerDir": "/var/lib/containers/storage/overlay/d558e2996c1e8e8eb14a6b1dff8be88d0e7c56c9b99d872265a98b5760741335/diff:/var/lib/containers/storage/overlay/707eeb55ebc2c5600ff8a80cd7657f5c0ff2913f763b2eb0eaa4cc079ebadbb9/diff:/var/lib/containers/storage/overlay/f1f0f964583ace4b905b7e33ccea241ce070ba53c9af547a9748c4b11b70bb30/diff:/var/lib/containers/storage/overlay/0cc07aba0259fc6e4b7b57685491e97b6f9de9d9b77fa27954c14b199017d333/diff:/var/lib/containers/storage/overlay/3a626bb08c24b5cc968d312bf5694aa87b6d9961c5f182c6bc138d8ca8ac13ee/diff",
                "MergedDir": "/var/lib/containers/storage/overlay/18bb651c4d12c4058c6f05339ba2b7a70d599bea91681f160fe5f450b395b52c/merged",
                "UpperDir": "/var/lib/containers/storage/overlay/18bb651c4d12c4058c6f05339ba2b7a70d599bea91681f160fe5f450b395b52c/diff",
                "WorkDir": "/var/lib/containers/storage/overlay/18bb651c4d12c4058c6f05339ba2b7a70d599bea91681f160fe5f450b395b52c/work"
            }
        },
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/webroot",
                "Destination": "/usr/local/apache2/htdocs/",
                "Driver": "",
                "Mode": "",
                "Options": [
                    "exec",
                    "rbind"
                ],
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
        "Dependencies": [],
        "NetworkSettings": {
            "EndpointID": "",
            "Gateway": "10.88.0.1",
            "IPAddress": "10.88.0.2",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "MacAddress": "0e:f3:ac:75:bb:6c",
            "Bridge": "",
            "SandboxID": "",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {
                "80/tcp": [
                    {
                        "HostIp": "",
                        "HostPort": "8080"
                    }
                ]
            },
            "SandboxKey": "/run/netns/cni-e8744179-964b-b311-651e-dbe108773e0a",
            "Networks": {
                "podman": {
                    "EndpointID": "",
                    "Gateway": "10.88.0.1",
                    "IPAddress": "10.88.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "0e:f3:ac:75:bb:6c",
                    "NetworkID": "podman",
                    "DriverOpts": null,
                    "IPAMConfig": null,
                    "Links": null
                }
            }
        },
        "ExitCommand": [
            "/usr/bin/podman",
            "--root",
            "/var/lib/containers/storage",
            "--runroot",
            "/run/containers/storage",
            "--log-level",
            "warning",
            "--cgroup-manager",
            "systemd",
            "--tmpdir",
            "/run/libpod",
            "--runtime",
            "runc",
            "--storage-driver",
            "overlay",
            "--storage-opt",
            "overlay.mountopt=nodev,metacopy=on",
            "--events-backend",
            "file",
            "container",
            "cleanup",
            "804debe95694391a50b4e597cda2cbe7d5e88bc89da9efaf2325c871fc3c1688"
        ],
        "Namespace": "",
        "IsInfra": false,
        "Config": {
            "Hostname": "804debe95694",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/apache2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "TERM=xterm",
                "container=podman",
                "HTTPD_SHA256=d0bbd1121a57b5f2a6ff92d7b96f8050c5a45d3f14db118f64979d525858db63",
                "HTTPD_PATCHES=",
                "HTTPD_PREFIX=/usr/local/apache2",
                "HTTPD_VERSION=2.4.53",
                "HOME=/root",
                "HOSTNAME=804debe95694"
            ],
            "Cmd": [
                "httpd-foreground"
            ],
            "Image": "docker.io/library/httpd:latest",
            "Volumes": null,
            "WorkingDir": "/usr/local/apache2",
            "Entrypoint": "",
            "OnBuild": null,
            "Labels": null,
            "Annotations": {
                "io.container.manager": "libpod",
                "io.kubernetes.cri-o.Created": "2022-03-24T17:39:49.78841153Z",
                "io.kubernetes.cri-o.TTY": "false",
                "io.podman.annotations.autoremove": "FALSE",
                "io.podman.annotations.init": "FALSE",
                "io.podman.annotations.privileged": "FALSE",
                "io.podman.annotations.publish-all": "FALSE",
                "org.opencontainers.image.stopSignal": "28"
            },
            "StopSignal": 28,
            "CreateCommand": [
                "podman",
                "container",
                "run",
                "--name",
                "webserver",
                "--detach=True",
                "--expose",
                "80",
                "--volume",
                "/webroot:/usr/local/apache2/htdocs/:exec",
                "--publish",
                "8080:80",
                "httpd"
            ],
            "Umask": "0022",
            "Timeout": 0,
            "StopTimeout": 10
        },
        "HostConfig": {
            "Binds": [
                "/webroot:/usr/local/apache2/htdocs/:exec,rw,rprivate,rbind"
            ],
            "CgroupManager": "systemd",
            "CgroupMode": "host",
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "k8s-file",
                "Config": null,
                "Path": "/var/lib/containers/storage/overlay-containers/804debe95694391a50b4e597cda2cbe7d5e88bc89da9efaf2325c871fc3c1688/userdata/ctr.log",
                "Tag": "",
                "Size": "0B"
            },
            "NetworkMode": "bridge",
            "PortBindings": {
                "80/tcp": [
                    {
                        "HostIp": "",
                        "HostPort": "8080"
                    }
                ]
            },
            "RestartPolicy": {
                "Name": "",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": [],
            "CapDrop": [
                "CAP_AUDIT_WRITE",
                "CAP_MKNOD"
            ],
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": [],
            "GroupAdd": [],
            "IpcMode": "private",
            "Cgroup": "",
            "Cgroups": "default",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "private",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": [],
            "Tmpfs": {},
            "UTSMode": "private",
            "UsernsMode": "",
            "ShmSize": 65536000,
            "Runtime": "oci",
            "ConsoleSize": [
                0,
                0
            ],
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": null,
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DiskQuota": 0,
            "KernelMemory": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": 0,
            "OomKillDisable": false,
            "PidsLimit": 2048,
            "Ulimits": [
                {
                    "Name": "RLIMIT_NOFILE",
                    "Soft": 1048576,
                    "Hard": 1048576
                },
                {
                    "Name": "RLIMIT_NPROC",
                    "Soft": 4194304,
                    "Hard": 4194304
                }
            ],
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "CgroupConf": null
        }
    }
]
[[email protected] devops]#

Apache Web Server in a Docker Container for RedHat-like systems

code with ❤️ in GitHub

Recap

Now you know how to set up Apache Web Server in a Podman Container for RedHat-like systems with Ansible. Subscribe to the YouTube channel, Medium, Website, Twitter, and Substack to not miss the next episode of the Ansible Pilot.

Academy

Learn the Ansible automation technology with some real-life examples in my

My book Ansible By Examples: 200+ Automation Examples For Linux and Windows System Administrator and DevOps

BUY the Complete PDF BOOK to easily Copy and Paste the 200+ Ansible code

Want to keep this project going? Please donate

Access the Complete Video Course and Learn Quick Ansible by 200+ Practical Lessons
Trustpilot
Follow me

Subscribe not to miss any new releases

FREE Top 10 Best Practices

Top 10 Best Practices of Ansible Automation: save time, reduce errors and stress