Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
gentoo:containers [2024/03/28 20:26] – willy | gentoo:containers [2025/05/06 05:55] (current) – willy | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Using Containers on Gentoo ====== | + | ====== |
- | Containers are a great tool that caters to some specific, and important, needs. But be aware that // | + | Containers are a great tool that caters to some specific, and important, needs. But be aware that // |
- | Bear in mind, always, that **containers** while being an astounding piece of technology, are **NOT** meant and have **NOT** been created with self-hosting | + | but since it's easy and simple to use containers |
Containerization technology can roughly be divided into two big categories: | Containerization technology can roughly be divided into two big categories: | ||
Line 9: | Line 9: | ||
* Clusters for deployment (Kubernetes and the like) | * Clusters for deployment (Kubernetes and the like) | ||
- | Over the course of time the use of Docker in the self-hosted world has increased so much that it's getting | + | Over the course of time the use of Docker in the self-hosted world has increased so much that today it's getting |
+ | |||
+ | Containers | ||
* Ease of deployment (docker compose up, and there you go) | * Ease of deployment (docker compose up, and there you go) | ||
* Ease of upgrade (docker pull, and there you go) | * Ease of upgrade (docker pull, and there you go) | ||
Line 15: | Line 17: | ||
* For developers, it's easier to provide a // | * For developers, it's easier to provide a // | ||
- | But are these really positive points of containers? I don't think so. The //ease of deployment// is because developers are too lazy to provide clear and nice deployment instruction or people are too lazy to read them. But this is **not the way of Linux**. //Ease of upgrade// again falls into the same objection, as well as //ease of management//, | + | At the beginning i was against using containers |
- | Now, let's see the negative points | + | I still think there are negative points |
* All services running as //root// (against Linux policies) | * All services running as //root// (against Linux policies) | ||
* Lots of duplicated services (how many postgress databases have you running around?) | * Lots of duplicated services (how many postgress databases have you running around?) | ||
- | * You don't understand what's going on | ||
* You don't learn anything new deploying your services | * You don't learn anything new deploying your services | ||
* When it breaks, it breaks hard because you don't know what broke | * When it breaks, it breaks hard because you don't know what broke | ||
Line 26: | Line 27: | ||
* It's back to Windows approach: black boxes everywhere that you can only roll-back or reinstall | * It's back to Windows approach: black boxes everywhere that you can only roll-back or reinstall | ||
- | Granted, all this **could** be fixed by fixing the docker images and maybe fixing your docker-compose files to improve things a bit, but who is really doing that? Wouldn' | + | In short, the spreading usage of Docker in the self-hosting world bring to Linux some bad practices and philosophy of the Windows world. Is this really necessary? Do we really want to become forced to be idiot-users who don't know any better? Is this really what means to be Linux users? |
- | + | ||
- | In short, the spreading usage of Docker in the self-hosting world bring to Linux the very worst practices and philosophy of the Windows world. Is this really necessary? Do we really want to become forced to be idiot-users who don't know any better? Is this really what means to be Linux users? | + | |
Question for your thoughts, now let's see how, at least, to use containers in a slightly better way. | Question for your thoughts, now let's see how, at least, to use containers in a slightly better way. | ||
Line 34: | Line 33: | ||
==== " | ==== " | ||
- | I prefer to avoid containers at all. But we are already at the point where some services are provided **only** as containers, and this is what i think the the **worse possible outcome** of this using containers more and more. **Where is the choice?** Why would i be forced to use some semi-proprietary technology to deploy Open Source services? | + | We are already at the point where some services are provided **only** as containers, and this is what i think the the **worse possible outcome** of this using containers more and more. **Where is the choice?** Why would i be forced to use some semi-proprietary technology to deploy Open Source services? |
I think that this is a trend that should be stopped. Please do provide containers and docker files, it's good and why not, but always also support bare-metal installations which means, please always provide **binary distributions** and **installation instructions** because without those, we will be nothing better than idiot-users and your service cannot be really called //open//. | I think that this is a trend that should be stopped. Please do provide containers and docker files, it's good and why not, but always also support bare-metal installations which means, please always provide **binary distributions** and **installation instructions** because without those, we will be nothing better than idiot-users and your service cannot be really called //open//. | ||
- | |||
===== Docker ===== | ===== Docker ===== | ||
Line 56: | Line 54: | ||
[[https:// | [[https:// | ||
- | * Doesn' | + | * Doesn' |
- | * Doesn' | + | * Doesn' |
* Integrates with OpenRC/ | * Integrates with OpenRC/ | ||
* It's fully Open Source | * It's fully Open Source | ||
Line 63: | Line 61: | ||
* It's not monolithic but it's actually a set of tools | * It's not monolithic but it's actually a set of tools | ||
* And it's also fully Docker-compatible (set alias docker=podman and you are dood to go, almost) | * And it's also fully Docker-compatible (set alias docker=podman and you are dood to go, almost) | ||
+ | * Doesn' | ||
Overall **Podman** is much more adherent to the Linux/Unix way of doing things. | Overall **Podman** is much more adherent to the Linux/Unix way of doing things. | ||
Line 68: | Line 67: | ||
Installing Podman is pretty easy since it's in Portage repository, but let's enable docker wrapper as well, so you can " | Installing Podman is pretty easy since it's in Portage repository, but let's enable docker wrapper as well, so you can " | ||
<code bash> | <code bash> | ||
- | > | + | echo " |
- | > emerge podman | + | emerge |
</ | </ | ||
Line 85: | Line 84: | ||
which i suggest to run as un-priviledged user to verify everything is working as non-root too. | which i suggest to run as un-priviledged user to verify everything is working as non-root too. | ||
- | Now, install | + | Podman is fully compatible with **Docker Compose**, so you should just emerge it and start using compose: |
+ | <code bash> | ||
+ | emerge -vp docker-compose | ||
+ | </ | ||
- | Follow my [[gentoo: | + | Or you can choose |
- | <file - podman-compose-1.0.6.ebuild> | + | <code bash> |
- | # Copyright 2024 Gentoo Authors | + | emerge |
- | # Distributed under the terms of the GNU General Public License v2 | + | </ |
- | EAPI=8 | + | of course, you need to pick one or the other. I am using podman-compose at this time. |
- | DISTUTILS_USE_SETUPTOOLS=rdepend | ||
- | PYTHON_COMPAT=( python3_{10..11} ) | ||
- | inherit distutils-r1 | + | === Podman rootless users === |
- | DESCRIPTION=" | + | When running a container rootless, which is the main point behind Podman, you might end up having some issues |
- | HOMEPAGE=" | + | |
- | SRC_URI=" | + | |
- | # | + | |
- | LICENSE=" | + | [[https:// |
- | SLOT=" | + | |
- | KEYWORDS=" | + | |
- | DEPEND="" | + | In short: when running rootless, the //user 0//, or root, of the container, will be mapped to your user ID, and any // |
- | RDEPEND=" | + | |
- | ${DEPEND} | + | |
- | dev-python/pyyaml[${PYTHON_USEDEP}] | + | |
- | dev-python/python-dotenv[${PYTHON_USEDEP}] | + | |
- | " | + | |
- | BDEPEND="" | + | |
- | </file> | + | |
- | as // | + | The easiest way to fix it, is to force your container to run... **as user 0**! In fact, since we are using rootless podman, that only means **as your own user** nad not actually root. |
- | I hope that this ebuild will be merged to Gentoo official repo soon. | ||
==== Podman networks ==== | ==== Podman networks ==== | ||
Line 127: | Line 114: | ||
To create a Podman subnet you need to run the following command after each reboot, as root: | To create a Podman subnet you need to run the following command after each reboot, as root: | ||
<code bash> | <code bash> | ||
- | > | + | podman network create my-container-net |
</ | </ | ||
Line 147: | Line 134: | ||
networks: | networks: | ||
my-container-net: | my-container-net: | ||
- | | + | </ |
| | ||
- | | + | I strongly suggest that you edit your docker compose files and ensure each service has it's own independent network. I will give more details for each service on it's respective page. |
+ | |||
+ | |||
+ | ==== Podman containers autostart ==== | ||
+ | |||
+ | Autostarting containers is pretty easy if you use SystemD, but even if you don't, and i don't, it's easy enough too. | ||
+ | |||
+ | <file - / | ||
+ | # | ||
+ | # Copyright 2024 Willy Garidol | ||
+ | # Distributed under the terms of the GNU General Public License v3 | ||
+ | |||
+ | depend() { | ||
+ | need localmount net | ||
+ | } | ||
+ | |||
+ | UC_LOG_PATH=/ | ||
+ | UC_SLOT=" | ||
+ | UC_USER=${USER: | ||
+ | UC_COMPOSER_FILE=${COMPOSER_FILE: | ||
+ | UC_CHOWN_DIR=${CHOWN_DIR} | ||
+ | if [ " | ||
+ | then | ||
+ | UC_HOME=${HOME: | ||
+ | fi | ||
+ | |||
+ | extra_commands=" | ||
+ | update() { | ||
+ | if [ " | ||
+ | then | ||
+ | COMMAND=" | ||
+ | stop | ||
+ | ebegin " | ||
+ | su - ${UC_USER} -c " | ||
+ | start | ||
+ | else | ||
+ | ebegin " | ||
+ | eend 255 | ||
+ | fi | ||
+ | } | ||
+ | |||
+ | description=${DESCRIPTION: | ||
+ | pidfile="/ | ||
+ | |||
+ | start_pre() { | ||
+ | if [ " | ||
+ | then | ||
+ | test -e " | ||
+ | test -e " | ||
+ | mkdir " | ||
+ | } && chown -R ${UC_USER} " | ||
+ | if [ -n " | ||
+ | then | ||
+ | chown -R ${UC_USER} ${UC_CHOWN_DIR} | ||
+ | fi | ||
+ | else | ||
+ | ebegin " | ||
+ | eend 255 | ||
+ | fi | ||
+ | } | ||
+ | |||
+ | |||
+ | start() { | ||
+ | ebegin " | ||
+ | COMMAND=" | ||
+ | ARGUMENTS=(compose -f ${UC_COMPOSER_FILE} up) | ||
+ | ebegin " ... ensuring nat table is loaded ..." | ||
+ | iptables -L -t nat &> /dev/null | ||
+ | ebegin " ... creating ' | ||
+ | podman network create ${UC_SLOT}-net &> /dev/null | ||
+ | su - " | ||
+ | start-stop-daemon -p ${pidfile} \ | ||
+ | -1 " | ||
+ | -2 " | ||
+ | -u ${UC_USER} \ | ||
+ | -d ${UC_HOME} \ | ||
+ | -b -m \ | ||
+ | --start | ||
+ | -- ${ARGUMENTS[@]} | ||
+ | eend $? | ||
+ | } | ||
+ | |||
+ | stop() { | ||
+ | ebegin " ... running ' | ||
+ | su - " | ||
+ | start-stop-daemon -p ${pidfile} \ | ||
+ | -u ${UC_USER} \ | ||
+ | -d ${UC_HOME} \ | ||
+ | --stop ${UC_SLOT} | ||
+ | eend $? | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | I assume you have a**service_name** that runs with a podman compose file as user **myuser**. | ||
+ | |||
+ | Just link the above script to your new service file: | ||
+ | <code bash> | ||
+ | ln -s / | ||
+ | </ | ||
+ | |||
+ | and create | ||
+ | <file - / | ||
+ | USER=myuser | ||
+ | DESCRIPTION=" | ||
+ | </ | ||
+ | |||
+ | and add the service to your desired runlevel: | ||
+ | <code bash> | ||
+ | rc-update add user-containers.service_name default | ||
+ | </ | ||
+ | |||
+ | That's it. | ||
+ | |||
+ | The above script also provide an " | ||
==== Using Podman for new containers ==== | ==== Using Podman for new containers ==== | ||
Line 155: | Line 256: | ||
Well, just replace any **docker** command with **podman** and you are good to go. Including the usual: | Well, just replace any **docker** command with **podman** and you are good to go. Including the usual: | ||
<code bash> | <code bash> | ||
- | > | + | podman compose up |
</ | </ | ||
Line 164: | Line 265: | ||
* Podman containers are not restarted at boot: i will give you instructions for those services as needed. | * Podman containers are not restarted at boot: i will give you instructions for those services as needed. | ||
* Networks needs to be explicitly declared and created as root. | * Networks needs to be explicitly declared and created as root. | ||
+ | |||
+ | |||
==== Migration from Docker to Podman ==== | ==== Migration from Docker to Podman ==== | ||
Line 171: | Line 274: | ||
Start by creating a non-privileged user (let's call it //service// to match the service name), let it point to where you stored the docker-compose.yml for the service (which should be **/ | Start by creating a non-privileged user (let's call it //service// to match the service name), let it point to where you stored the docker-compose.yml for the service (which should be **/ | ||
<code bash> | <code bash> | ||
- | > | + | useradd -d / |
- | > chown service: | + | chown service: |
</ | </ | ||
Line 179: | Line 282: | ||
Now, most probably all you need to do is the classic (but rewritten): | Now, most probably all you need to do is the classic (but rewritten): | ||
<code bash> | <code bash> | ||
- | > | + | su - service |
- | > podman compose -f docker-compose.yml up | + | podman compose -f docker-compose.yml up |
</ | </ | ||
Line 191: | Line 294: | ||
If you need to export your images from Docker to Podman (you don't if they are public images), as root, export all docker images relevant to your service (you can see them in the composer file), use //docker image ls// to list images and //docker save -o ...// to save each one of them as a tar file: | If you need to export your images from Docker to Podman (you don't if they are public images), as root, export all docker images relevant to your service (you can see them in the composer file), use //docker image ls// to list images and //docker save -o ...// to save each one of them as a tar file: | ||
<code bash> | <code bash> | ||
- | > | + | mkdir / |
- | > docker image ls | + | docker image ls |
- | > docker image save -o / | + | docker image save -o / |
- | > chown service: | + | chown service: |
</ | </ | ||
(repeat for each image for the service!) | (repeat for each image for the service!) | ||
Line 200: | Line 303: | ||
If your container uses also volumes, copy them to your //service// user, as root: | If your container uses also volumes, copy them to your //service// user, as root: | ||
<code bash> | <code bash> | ||
- | > | + | mkdir / |
- | > cp -a / | + | cp -a / |
- | > chown service: | + | chown service: |
</ | </ | ||
(repeat for each volume for the service!) | (repeat for each volume for the service!) | ||
Line 208: | Line 311: | ||
Now, as user //server//, import the images and create the volumes: | Now, as user //server//, import the images and create the volumes: | ||
<code bash> | <code bash> | ||
- | > | + | su - service |
- | > podman load -i docker-export/ | + | podman load -i docker-export/ |
</ | </ | ||
Line 225: | Line 328: | ||
<code bash> | <code bash> | ||
- | > | + | cp -a / |
</ | </ | ||
Line 235: | Line 338: | ||
- ping is restricted and cannot b performed from containers. If you need to enable it, type as root: | - ping is restricted and cannot b performed from containers. If you need to enable it, type as root: | ||
<code bash> | <code bash> | ||
- | > | + | sysctl -w " |
</ | </ | ||
This can be made permanent in **/ | This can be made permanent in **/ | ||
Line 243: | Line 346: | ||
- Running as simple user a container will not be allowed to bind to ports under 1024. Some ill-designed containers will insist on this. The only recurse (except don't use such broken images) is to allow ports for normal users with: | - Running as simple user a container will not be allowed to bind to ports under 1024. Some ill-designed containers will insist on this. The only recurse (except don't use such broken images) is to allow ports for normal users with: | ||
<code bash> | <code bash> | ||
- | > | + | sysctl -w " |
</ | </ | ||
This can be made permanent in **/ | This can be made permanent in **/ | ||
- | - Podman containers are not restarted at boot. To achieve the same behaviour as Docker, my suggestion is to create a startup file under **/etc/local.d/** where you **su** as your unpriviledged user and simply do a **podman compose up**, that's it. | + | - Podman containers are not restarted at boot. To achieve the same behaviour as Docker, my suggestion is to follow my lead on leveraging |
- | An example for a service //service// owned by user //service// which required // | + | If you want to do things manually, just keen in mind that you need to ensure |
- | <file - 50-service.start> | + | <code> |
- | #!/bin/bash | + | |
modprobe iptable_nat | modprobe iptable_nat | ||
iptable -L -t nat | iptable -L -t nat | ||
- | podman network create service-net | + | </code> |
- | su - service -c " | + | |
- | </file> | + | |
- | + | ||
- | Note that unless you already load the NAT iptable module, you should do it now as it will block containers to properly start, if missing, and for some reason podman will not load it automatically. | + | |
- | + | ||
- | + | ||
- | And don't forget a **/ | + | |
- | <file - 50-service.stop> | + | |
- | # | + | |
- | su - service -c " | + | |
- | </ | + | |
- | + | ||
- | Remember to set both scripts are **+x** permission. | + | |