No video this time, just steps.
After getting tired of LinuxMint (the update from 19.3 to 20.04 didn't work right), I switched back to Fedora. Originally I switched from Fedora to LinuxMint to try it out thinking it would be more stable. Thus far... nope, but it's my fault for buying a laptop with an AMD CPU. Ubuntu would likely be the better more stable desktop choice, but I prefer flatpak to snapd, and my desktop already runs Ubuntu. Ubuntu is solid, just why stick to only one distro?
I digress.
This blog is focused on running a LAMP stack with Podman. I mentioned it briefly in the Intro to Virtualization and Containers video, but essentially Podman is the more open source version of Docker-CE and works almost - key word there - like Docker. However, it doesn't officially have a feature like Docker Compose to build a whole bunch of containers via a yaml file - they need to be built and connected manually...
The nice thing about Podman is that it supports the latest CGroups, and is preinstalled on Fedora (some more background). Fedora 32, by default, doesn't actually support Docker because Docker does not yet support the new CGroups. So Podman is essentially more up-to-date, potentially more secure, and much more of a headache to setup.
Let's get into it.
Need to create a network for the podman containers- default doesn't seem to have a DNS as I understand.
sudo podman network create <-- Likely better to give a name at the end, just type a name as I understand.
sudo podman network ls <-- Find the name; in the below it's cni-podman1 which is a default name when none is given.
MySQL container
Run sudo podman run --name=mysqltest -p=3306:3306 -d --network=cni-podman1 -e MYSQL_ROOT_PASSWORD=mysqltest -e lower_case_table_names=1 mysql:5.7
Note: The run command in Docker/Podman is very similar. We give the container a name, map ports <host>:<container>, -d is detach so the container doesn't eat your terminal, define networking, then -e is environment variables like defined in the YAML file. At the end we name the image to pull from; if not already installed this will automatically pull from docker.io, though podman searchs the RedHat and CentOS image hubs first.
PHPMYADMIN container
Run sudo podman run --name=PHPMAtest -p=8081:80 --network=cni-podman1 -e MYSQL_ROOT_PASSWORD=mysqltest -e PMA_HOST=mysqltest -e PMA_PORT=3306 -d phpmyadmin/phpmyadmin:latest
Open the browser and go to localhost:8081, upon seeing PHPMyAdmin use username: root and the password as defined, in this case mysqltest. This should work if your Podman networking is set properly, and no awkward firewall rules.
PHP / Apache image
Create a directory Podman-LAMP and a sub-directory src under it (any name for either directory will do so long as your commands are consistent). Under Podman-LAMP create a Dockerfile with the below information information.
FROM php:7.0-apache
RUN docker-php-ext-install mysqli
EXPOSE 80
Like in Docker, Podman recognizes Dockerfile and will build the container image based on the supplied parameters. We first build the container in order to install the mysqli, and allow port 80 <- port 443 may also be needed if you require HTTPS. We are building the container rather than just running it because we want to install mysqli and expose port 80.
Run chmod -R 755 src to allow the Apache server access to files in the src directory.
To build the new image run sudo podman build ./Podman-LAMP --tag apachephppod. The --tag option gives the image a name.
Run the PHP / Apache container
Run sudo podman run --name=APpod -v ./Podman-LAMP/src:/var/www/html:z -p 80:80 --network=cni-podman1 -d apachephppod
**The :z in the mount command is important for SELinux issues - Docker doesn't have those issues in my experience could also be related to the CGroups and versioning that I've tried. That said other users have mentioned the :z with Docker and SElinux and could be that my previous experience of running Docker on Fedora had yet to enable the latest SELinux functionality.
Once all of that is setup you can connect to the database using msqli and set the MySQL host name as the name of the MySQL container - mysqltest in this example. This can be done in place of the IP of the local host or Docker network though it might work as well.
Example: $mysqli = new mysqli('mysqltest', 'root', 'password', 'joescoffee');
Where: (<host address/host name>, <user>, <password>, <database>)
With everything created, to stop/start the containers just follow the below commands. Information will be retained because the containers have been named, and the Apache/PHP container has a mapped volume. If you run the run command again it will throw an error since the container with that name exists, and if you keep running run with new names it just keeps adding containers.
sudo podman container start mysqltest APpod PHPMAtest
sudo podman container stop mysqltest APpod PHPMAtest
This was a good exercise for myself. Learning how to connect separate containers together helped reinforce a lot of my understanding about the technology, both Docker and Podman. The SELinux requiring :z threw me the most, but thankfully poking around Google and forum threads pointed me in the right direction. I hope this blog can help save you the hours I spent getting it working.
This comment has been removed by the author.
ReplyDeleteThis comment has been removed by the author.
DeleteMany thanks, my first day with podman and its nice to be able to work through the example as a learning exercise.
ReplyDeleteThere is one thing though, which is that with the command :
sudo podman run --name=APpod -v ./Podman-LAMP/src:/var/www/html:z -p 80:80 --network=cni-podman1 -d apachephppod
I get the following error:
Error: failed to expose ports via rootlessport: "cannot expose privileged port 80, you might need to add \"net.ipv4.ip_unprivileged_port_start=0\" (currently 1024) to /etc/sysctl.conf, or choose a larger port number (>= 1024): listen tcp 0.0.0.0:80: bind: permission denied\n"
Apparently this is a limitation of non-privileged/non-root containers.
Perhaps you meant to write:
sudo podman run --name=APpod -v ./Podman-LAMP/src:/var/www/html:z -p 8080:80 --network=cni-podman1 -d apachephppod
...in order to bind port 80 in the container to port 8080 on the host?
But then I am left asking myself why the dockerfile command EXPOSE 80?
Although the podman build command pulls in the following image:
Deletequay.io/libpod/rootless-cni-infra
which I think is being run when the apachephppod starts? Not sure why currently.
Ok, so I have now read and understood the whole rootless vs rootful container issue, and can see that because you are using sudo, your container is running as root, which means it has full capabilities. It is suggested to drop-caps on rootful containers and then just add back in the caps you need.
DeleteI still prefer to run rootless, and will attempt to port forward or use a namespace with slirp4netns.
Ok, so I have been working up to creating a pod with a database, python running django and gunicorn and nginx, but along the way, my python and nginx container both currently use a bind mount to a directory on the host.
ReplyDeleteI haven't found any useful articles that describe the security implications of mounting using the -v option. After all, if pod containerisation is to isolate the bulk of the code from the host, then isn't a -v mount bypassing the point of the isolation to some extent?
Or does one use the -v mount during development and then move it back to the pod when development is finished?
So for the purposes of this example I didn't use a pod, honestly I didn't realize it was possible when first creating the LAMP stack so went the network route which needed the root permission if memory serves. I should probably look to the pod approach more - might allow for doing the same thing without root.
DeleteAs I understand the -v or volume is to mount a directory to the container which makes interacting with the data simpler - /var/www/html/ in this example. It isn't 100% necessary, but helps with development. Once the container is created you need to keep the volume parameter unless you copy the data and create a new container based on that image, however. As a best practice I would imagine that access to the host should be more protected vs the container running on the host - either with port forwarding or other methods. Anyone with access to the host would be able to thrash the containers for sure.
Sorry for the late reply, I don't check the comments much. Here is some more on pods and podman as well - https://fedoramagazine.org/podman-pods-fedora-containers/. I hope it helps and good luck with your work and development.