In this lab you will deconstruct an application into microservices, creating a multi-container application. In this process we explore the challenges of networking, storage and configuration.
This lab should be performed on YOUR ASSIGNED AWS VM as ec2-user unless otherwise instructed.
NOTE: In the steps below we use vi to edit files. If you are unfamiliar, this is a good beginner's guide. In short, "ESC" switches to command mode, "i" let's you edit, "wq" let's you save and exit, "q!" let's you exit without saving (all executed in command mode).
Expected completion: 20-30 minutes
In the previous lab we created an "all-in-one" application. Let's enter the container and explore.
$ sudo podman exec -t bigapp /bin/bashFrom the container namespace list the log directories.
[CONTAINER_NAMESPACE]# ls -l /var/log/We see httpd and mariadb. These are the services that make up the Wordpress application.
We saw in the Dockerfile that port 80 was exposed. This is for the web server. Let's look at the mariadb logs for the port the database uses:
[CONTAINER_NAMESPACE]# grep port /var/log/mariadb/mariadb.logThis shows port 3306 is used.
The Wordpress tar file was extracted into /var/www/html. List the files.
[CONTAINER_NAMESPACE]# ls -l /var/www/htmlThese are sensitive files for our application and it would be unfortunate if changes to these files were lost. Currently the running container does not have any associated "volumes", which means that if this container dies all changes will be lost. This mount point in the container should be backed by a "volume". Later in this lab, we'll use a directory from our host machine to back the "volume" to make sure these files persist.
Inspect the mariadb.log file to discover the database directory.
[CONTAINER_NAMESPACE]# grep databases /var/log/mariadb/mariadb.logAgain, we have found some files that are in need of some non-volatile storage. The /var/lib/mysql directory should also be mounted to persistent storage on the host.
Now that we've inspected the container stop and remove it. podman ps -ql (don't forget sudo) prints the ID of the latest created container. First you will need to exit the container.
[CONTAINER_NAMESPACE]# exit
$ sudo podman stop $(sudo podman ps -ql)
$ sudo podman rm $(sudo podman ps -ql)If we are confident in what we are doing we can also "single-line" the above with sudo podman rm -f $(sudo podman ps -ql) by itself.
Now we will develop the two images. Using the information above and the Dockerfile from Lab 2 as a guide, we will create Dockerfiles for each service. For this lab we have created a directory for each service with the required files for the service. Please explore these directories and check out the contents and the startup scripts.
$ mkdir ~/workspace
$ cd ~/workspace
$ cp -R ~/summit-2018-container-lab/labs/lab3/mariadb .
$ cp -R ~/summit-2018-container-lab/labs/lab3/wordpress .
$ ls -lR mariadb
$ ls -lR wordpress-
In a text editor create a file named
Dockerfilein themariadbdirectory. (There is a reference file in themariadbdirectory if needed)$ vi mariadb/Dockerfile -
Add a
FROMline that uses a specific image tag. Also addMAINTAINERinformation.FROM registry.access.redhat.com/rhel7:7.5-231 MAINTAINER Student <[email protected]> -
Add the required packages. We'll include
yum clean allat the end to clear the yum cache.RUN yum -y install --disablerepo "*" --enablerepo rhel-7-server-rpms \ mariadb-server openssl psmisc net-tools hostname && \ yum clean all -
Add the dependent scripts and modify permissions to support non-root container runtime.
ADD scripts /scripts RUN chmod 755 /scripts/* && \ MARIADB_DIRS="/var/lib/mysql /var/log/mariadb /run/mariadb" && \ chown -R mysql:0 ${MARIADB_DIRS} && \ chmod -R g=u ${MARIADB_DIRS} -
Add an instruction to expose the database port.
EXPOSE 3306 -
Add a
VOLUMEinstruction. This ensures data will be persisted even if the container is lost. However, it won't do anything unless, when running the container, host directories are mapped to the volumes.VOLUME /var/lib/mysql -
Switch to a non-root
USERuid. The default uid of the mysql user is 27.USER 27 -
Finish by adding the
CMDinstruction.CMD ["/bin/bash", "/scripts/start.sh"]
Save the file and exit the editor.
Now we'll create the Wordpress Dockerfile. (As before, there is a reference file in the wordpress directory if needed)
-
Using a text editor create a file named
Dockerfilein thewordpressdirectory.$ vi wordpress/Dockerfile -
Add a
FROMline that uses a specific image tag. Also addMAINTAINERinformation.FROM registry.access.redhat.com/rhel7:7.5-231 MAINTAINER Student <[email protected]> -
Add the required packages. We'll include
yum clean allat the end to clear the yum cache.RUN yum -y install --disablerepo "*" --enablerepo rhel-7-server-rpms \ httpd php php-mysql php-gd openssl psmisc && \ yum clean all -
Add the dependent scripts and make them executable.
ADD scripts /scripts RUN chmod 755 /scripts/* -
Add the Wordpress source from gzip tar file. podman will extract the files. Also, modify permissions to support non-root container runtime. Switch to port 8080 for non-root apache runtime.
COPY latest.tar.gz /latest.tar.gz RUN tar xvzf /latest.tar.gz -C /var/www/html --strip-components=1 && \ rm /latest.tar.gz && \ sed -i 's/^Listen 80/Listen 8080/g' /etc/httpd/conf/httpd.conf && \ APACHE_DIRS="/var/www/html /usr/share/httpd /var/log/httpd /run/httpd" && \ chown -R apache:0 ${APACHE_DIRS} && \ chmod -R g=u ${APACHE_DIRS} -
Add an instruction to expose the web server port.
EXPOSE 8080 -
Add a
VOLUMEinstruction. This ensures data will be persisted even if the container is lost.VOLUME /var/www/html/wp-content/uploads -
Switch to a non-root
USERuid. The default uid of the apache user is 48.USER 48 -
Finish by adding the
CMDinstruction.CMD ["/bin/bash", "/scripts/start.sh"]
Save the Dockerfile and exit the editor.
Now we are ready to build the images to test our Dockerfiles.
-
Build each image. When building an image podman requires the path to the directory of the Dockerfile.
$ sudo podman build -t mariadb mariadb/ $ sudo podman build -t wordpress wordpress/ -
If the build does not succeed then resolve the issue and build again. Once successful, list the images.
$ sudo podman images -
Create the local directories for persistent storage. Match the directory permissions we set in our Dockerfiles.
$ mkdir -p ~/workspace/pv/mysql ~/workspace/pv/uploads $ sudo chown -R 27 ~/workspace/pv/mysql $ sudo chown -R 48 ~/workspace/pv/uploads -
Run the wordpress image first. See an explanation of all the
podman runoptions we will be using below:
-dto run in daemonized mode-v <host/path>:<container/path>:zto mount (technically, "bindmount") the directory for persistent storage. The :z option will label the content inside the container with the SELinux MCS label that the container uses so that the container can write to the directory. Below we'll inspect the labels on the directories before and after we run the container to see the changes on the labels in the directories-p <host_port>:<container_port>to map the container port to the host port
$ ls -lZd ~/workspace/pv/uploads
$ sudo podman run -d -p 8080:8080 -v ~/workspace/pv/uploads:/var/www/html/wp-content/uploads:z -e DB_ENV_DBUSER=user -e DB_ENV_DBPASS=mypassword -e DB_ENV_DBNAME=mydb -e DB_HOST=0.0.0.0 -e DB_PORT=3306 --name wordpress wordpressNote: See the difference in SELinux context after running with a volume & :z.
$ ls -lZd ~/workspace/pv/uploads
$ sudo podman exec wordpress ps aux #we can also directly exec commands in the containerCheck volume directory ownership inside the container
$ sudo podman exec wordpress stat --format="%U" /var/www/html/wp-content/uploadsNow we can check out how wordpress is doing
$ sudo podman logs wordpress
$ sudo podman ps
$ curl -L http://localhost:8080 #note we indicated the port to use in the run command aboveNote: the curl command returns an error but demonstrates
a response on the port.
- Bring up the database (mariadb) for the wordpress instance. For the mariadb container we need to specify an additional option to make sure it is in the same "network" as the apache/wordpress container and not visible outside that container:
--network=container:<alias>to link to the wordpress container
$ ls -lZd ~/workspace/pv/mysql
$ sudo podman run -d --network=container:wordpress -v ~/workspace/pv/mysql:/var/lib/mysql:z -e DBUSER=user -e DBPASS=mypassword -e DBNAME=mydb --name mariadb mariadbNote: See the difference in SELinux context after running w/ a volume & :z.
$ ls -lZd ~/workspace/pv/mysql
$ ls -lZ ~/workspace/pv/mysql
$ sudo podman exec mariadb ps auxCheck volume directory ownership inside the container
$ sudo podman exec mariadb stat --format="%U" /var/lib/mysqlNow we can check out how the database is doing
$ sudo podman logs mariadb
$ sudo podman ps
$ sudo podman exec mariadb curl localhost:3306
$ sudo podman exec mariadb mysql -u user --password=mypassword -e 'show databases'
$ curl localhost:3306 #as you can see the db is not generally visible
$ curl -L http://localhost:8080 #and now wp is happier!You may also load the Wordpress application in a browser to test its full functionality @ http://<YOUR AWS VM PUBLIC DNS NAME HERE>:8080.
Let's deploy a simple registry to store our images.
Inspect the Dockerfile that has been prepared.
$ cd ~/summit-2018-container-lab/labs/lab3/
$ cat registry/DockerfileBuild & run the registry
$ sudo podman build -t registry registry/
$ sudo podman run --name registry -p 5000:5000 -d registryConfirm the registry is running.
$ sudo podman psPush the images
$ sudo podman images
$ sudo podman push --tls-verify=false mariadb localhost:5000/mariadb
$ sudo podman push --tls-verify=false wordpress localhost:5000/wordpressRemove the mariadb and wordpress containers.
$ sudo podman rm -f mariadb wordpress
$ sudo podman ps -aIn the next lab we introduce container orchestration via OpenShift.