I will create a photo gallery running in a Podman container on a RHEL EC2 instance, where the photos displayed by the web site are stored on the EC2 instances connected to AWS Elastic File System(EFS) across multiple Availability Zones(AZ’s).
So what is Podman? Podman is a daemonless container engine for developing, managing, and running OCI Containers on your Rat Hat Enterprise Linux (RHEL ) System.
As far as Amazon Elastic File System (Amazon EFS) goes, it provides a simple, serverless, set-and-forget, elastic file system that lets you share file data without provisioning or managing storage. It can be used with AWS Cloud services and on-premises resources, and is built to scale on demand to petabytes without disrupting applications. With Amazon EFS, you can grow and shrink your file systems automatically as you add and remove files, eliminating the need to provision and manage capacity to accommodate growth.
In this post for the photo gallery we will use the photoshow container image. https://hub.docker.com/r/linuxserver/photoshow
What we will see in the post:
The Podman container will run in a RHEL EC2 instance, and use the local filesystem on the EC2 instance to store the images (This is without HA).
We will do exactly what we did in step1 , but this time we store the images on an EFS file system. (Storage level HA)
We make the solution HA by adding a second EC2 instance on another AZ, and adding an Application Load Balancer in front of it. (Compute level HA added)
We take care of scaling the solution by adding an Auto Scaling Group. (Scaling added)
Step 1:
Let's start by downloading the photoshow image
[ec2-user@ip-172-31-58-150 ~]$ sudo podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
ghcr.io/linuxserver/photoshow latest eb0ad054517e 5 days ago 222 MB
Just making sure that there are no containers running on the EC2 instance.
[ec2-user@ip-172-31-58-150 ~]$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
We start by creating a directory on the host machine, and then creating a file in that directory.
[ec2-user@ip-172-31-58-150 ~]$ pwd
/home/ec2-user
[ec2-user@ip-172-31-58-150 ~]$ ls -l photo/
total 8
drwxrwxr-x. 7 ec2-user ec2-user 64 May 20 00:16 config
drwxrwxr-x. 2 ec2-user ec2-user 4096 May 20 03:12 pictures
drwxrwxr-x. 4 ec2-user ec2-user 32 May 20 00:16 thumb
Now we run the container with the podman command with -v to point the source and where we want it mounted into the container.
[ec2-user@ip-172-31-58-150 ~]$ sudo podman run -d \
--name=photoshow \
-e PUID=1000 -e PGID=1000 -e TZ=Europe/London -p 8080:80 \
-v /home/ec2-user/photo/config:/config:Z \
-v /home/ec2-user/photo/pictures:/Pictures:Z \
-v /home/ec2-user/photo/thumb:/Thumbs:Z \
--restart unless-stopped linuxserver/photoshow
The :Z will ensure the proper SeLinux context is set.
[ec2-user@ip-172-31-58-150 ~]$ sudo podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0d011645d26d linuxserver/photoshow 9 minutes ago Up 9 minutes ago 0.0.0.0:8080->80/tcp photoshow
We download a few images into the /photo/pictures directory of the host EC2 instance using wget.
[ec2-user@ip-172-31-58-150 ~]$ ls photo/pictures/
Argentina_WC.png FIFA_World_Cup.jpg Germany_WC.png Korea-Japan_WC.png Qatar_WC.png SouthAfrica_WC.png USA_WC.png
Brasil_WC.png France_WC.png Italia_WC.png Mexico_WC.png Russia_WC.png Spain_WC.png WGermany_WC.png
[ec2-user@ip-172-31-58-150 ~]$
This is just to show that no volumes were indeed created
[ec2-user@ip-172-31-58-150 images]$ sudo podman volume ls
Let's do an “inspect” of the container to see what was Mounted
[ec2-user@ip-172-31-58-150 images]$ sudo podman inspect photoshow
…….
…….
…….
"Mounts": [
{
"Type": "bind",
"Name": "",
"Source": "/home/ec2-user/photo/thumb",
"Destination": "/Thumbs",
"Driver": "",
"Mode": "",
"Options": [
"rbind"
],
"RW": true,
"Propagation": "rprivate"
},
{
"Type": "bind",
"Name": "",
"Source": "/home/ec2-user/photo/config",
"Destination": "/config",
"Driver": "",
"Mode": "",
"Options": [
"rbind"
],
"RW": true,
"Propagation": "rprivate"
},
{
"Type": "bind",
"Name": "",
"Source": "/home/ec2-user/photo/pictures",
"Destination": "/Pictures",
"Driver": "",
"Mode": "",
"Options": [
"rbind"
],
"RW": true,
"Propagation": "rprivate"
}
],
…….
…….
Lets log into the container and check the directories that we created:
[ec2-user@ip-172-31-58-150 ~]$ sudo podman exec -it photoshow /bin/bash
root@0d011645d26d:/#
root@0d011645d26d:/#
root@0d011645d26d:/# ls
Pictures app config dev etc init libexec mnt proc run srv tmp var
Thumbs bin defaults docker-mods home lib media opt root sbin sys usr version.txt
root@0d011645d26d:/# ls -l /Pictures /config /Thumbs
/Pictures:
total 2456
-rw-rw-r-- 1 abc users 70015 Apr 9 00:56 Argentina_WC.png
-rw-rw-r-- 1 abc users 173472 May 20 03:53 Brasil_WC.png
-rw-rw-r-- 1 abc users 879401 May 20 03:53 FIFA_World_Cup.jpg
-rw-rw-r-- 1 abc users 81582 Jul 17 2018 France_WC.png
-rw-rw-r-- 1 abc users 124180 May 20 03:53 Germany_WC.png
-rw-rw-r-- 1 abc users 84614 Jul 17 2018 Italia_WC.png
-rw-rw-r-- 1 abc users 126259 Sep 13 2019 Korea-Japan_WC.png
-rw-rw-r-- 1 abc users 157670 Jul 17 2018 Mexico_WC.png
-rw-rw-r-- 1 abc users 125000 May 20 03:53 Qatar_WC.png
-rw-rw-r-- 1 abc users 188832 May 20 03:53 Russia_WC.png
-rw-rw-r-- 1 abc users 248316 May 20 03:53 SouthAfrica_WC.png
-rw-rw-r-- 1 abc users 104383 May 19 10:36 Spain_WC.png
-rw-rw-r-- 1 abc users 98021 Jul 18 2018 USA_WC.png
-rw-rw-r-- 1 abc users 26622 Jul 18 2018 WGermany_WC.png
/Thumbs:
total 4
drwxr-x--- 2 abc users 67 May 20 03:54 Conf
drwxr-x--- 2 abc users 4096 May 20 04:13 Thumbs
/config:
total 0
drwxr-xr-x 2 abc users 38 May 20 01:16 keys
drwxr-xr-x 4 abc users 54 May 20 02:00 log
drwxrwxr-x 3 abc users 42 May 20 01:16 nginx
drwxr-xr-x 2 abc users 44 May 20 01:16 php
drwxrwxr-x 3 abc users 41 May 20 01:16 www
root@0d011645d26d:/#
Go to http://54.202.174.232:8080 to check the Photo Gallery
Gooooal!!!
Step 2:
This is cool, but is the data highly available - meaning what happens if the EC2 goes down, can I still access my images in this case?
Our application was using the local filesystem in the previous scenario. To make the data HA (Highly Available) lets use EFS to store our images. You will see below how to set up EFS and use it with our application container running in Podman.
Create and EFS filesystem, in this case called “demo”
On the EC2 host mount the EFS filesystem
[ec2-user@ip-172-31-58-150 pictures]$ cat /etc/fstab
#
# /etc/fstab
# Created by anaconda on Sat Oct 31 05:00:52 2020
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=949779ce-46aa-434e-8eb0-852514a5d69e / xfs defaults 0 0
fs-33656734.efs.us-west-2.amazonaws.com:/ /mnt/efs_drive nfs defaults,vers=4.1 0 0
Lets mount /mnt/efs_drive
[ec2-user@ip-172-31-58-150 pictures]$ sudo mount /mnt/efs_drive
[ec2-user@ip-172-31-58-150 pictures]$ df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 3.8G 0 3.8G 0% /dev
tmpfs 3.8G 168K 3.8G 1% /dev/shm
tmpfs 3.8G 17M 3.8G 1% /run
tmpfs 3.8G 0 3.8G 0% /sys/fs/cgroup
/dev/xvda2 10G 9.6G 426M 96% /
tmpfs 777M 68K 777M 1% /run/user/1000
fs-33656734.efs.us-west-2.amazonaws.com:/ 8.0E 0 8.0E 0% /mnt/efs_drive
Run the container using Podman
[ec2-user@ip-172-31-58-150 ~]$ sudo podman run -d --name=photoshow -e PUID=1000 -e PGID=1000 -e TZ=Europe/London -p 8080:80 --mount type=bind,source=/mnt/efs_drive/photo/config,destination=/config --mount type=bind,source=/mnt/efs_drive/photo/pictures/,destination=/Pictures --mount type=bind,source=/mnt/efs_drive/photo/thumb/,destination=/Thumbs --restart unless-stopped ghcr.io/linuxserver/photoshow
95c78443d893334c4d5538dc03761f828d5e7a59427c87ae364ab1e7f6d30e15
[ec2-user@ip-172-31-58-150 ~]$
[ec2-user@ip-172-31-58-150 ~]$ sudo podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
95c78443d893 ghcr.io/linuxserver/photoshow 18 seconds ago Up 17 seconds ago 0.0.0.0:8080->80/tcp photoshow
[ec2-user@ip-172-31-58-150 ~]$
Let's inspect the container
[ec2-user@ip-172-31-58-150 ~]$ sudo podman inspect photoshow
……………
……………
……………
"Mounts": [
{
"Type": "bind",
"Name": "",
"Source": "/mnt/efs_drive/photo/config",
"Destination": "/config",
"Driver": "",
"Mode": "",
"Options": [
"rbind"
],
"RW": true,
"Propagation": "rprivate"
},
{
"Type": "bind",
"Name": "",
"Source": "/mnt/efs_drive/photo/pictures",
"Destination": "/Pictures",
"Driver": "",
"Mode": "",
"Options": [
"rbind"
],
"RW": true,
"Propagation": "rprivate"
},
{
"Type": "bind",
"Name": "",
"Source": "/mnt/efs_drive/photo/thumb",
"Destination": "/Thumbs",
"Driver": "",
"Mode": "",
"Options": [
"rbind"
],
"RW": true,
"Propagation": "rprivate"
}
],
……………
……………
…………...
Step 3:
This is fine, but what if the EC2 instance goes down? I have data in an EFS filesystem but how are the clients going to access it?
For this we have to make our compute and storage both HA. Our storage is already HA because of EFS, but now let's make the EC2 instance also HA.
For that we first create an image (AMI) of our running EC2 instance as shown below in the screen shots, and bring a new EC2 instance in a different Availability Zone(AZ). Both our instance will now be accessing the same data that is stored on EFS
Lets add an Application Load Balancer to distribute the client requests to the two EC2 instance in the two AZ’s
The Application Load Balancer forwards the requests to the Target group that includes the two EC2 instances hosting our application containers.
Enter the DNS name of the Load Balancer with port 8080 in the web browser (photoshow-lb-207083175.us-west-2.elb.amazonaws.com:8080) to connect to the application.
Goooal!!!
Step 4:
So far so good, but happens when our requests increase and we need additional resources to handle the client requests?
Ah ha, that is exactly where the Autoscaler comes into picture. I added an Auto Scaling group called photoshow-asg with Desired Capacity of 1, Minimum capacity of 1, and Maximum capacity of 3 to handle any increase in the user requests.
I tested to see if the Photo gallery can still be accessed from the URL, and the scaling of the EC2 instances based on the load.
Goooal!!!
Ok, but I don’t want to be giving the DNS name of a Load Balancer to family and friends to check out my photos, how uncool is that!
Valid point! That is where Route 53 can help. I have a domain register with Route 53, and I’m going to use it to access the photo gallery.
Go to Route 53 -> Hosted Zone -> <your registered domain> and create a CNAME record type pointing to the Load Balancer DNS name
Conclusion:
In this post we have seen how a Podman Containerized application running in RHEL can connect to Amazon EFS. In the following posts we will look into other storage features for Podman Containers like volumes, and we can use it in a containerized solution.