Container (Docker/Podman) ######################### Install ======= If not on a base Ubuntu image, :code:`cat /etc/upstream-release/lsb-release` may give you a result for the release you are on. .. code-block:: bash sudo apt update sudo apt install -y apt-transport-https ca-certificates curl software-properties-common curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt update apt-cache policy docker-ce sudo apt install -y docker-ce sudo systemctl status docker You may want to add your user to the dockre group: :code:`sudo usermod -aG docker $USER` followed by :code:`exec bash -l` and/or :code:`newgrp docker` to take immediate effect. Portainer ========= Update ****** .. code-block:: bash docker stop portainer docker rm portainer docker image rm portainer/portainer-ce docker run -d -p 8000:8000 -p 9000:9000 -p 9443:9443 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest Run Container without immediate exiting *************************************** On container Setup go to :code:`Advanced container settings` and select :code:`Interactive & TTY` (or just TTY) under :code:`Console`. Next check the :code:`Command`, it should read something similar to :code:`/bin/sh` or :code:`/bin/bash` View Network ============ .. code-block:: bash podman network ls --format "{{.Name}}: {{range .Subnets}}{{.Subnet}} {{end}}" Set CPU and Memory Limit ======================== .. code-block:: bash podman machine stop podman machine set --cpus 2 --memory 2048 podman machine start podman machine set --cpus 12 --memory 36864 --disk-size 500 If Images are reported as in use, but no container is running ============================================================= .. code-block:: bash podman ps --all --storage podman rmi --force _image_id_ View Usage ========== .. code-block:: bash podman system df https://docs.podman.io/en/latest/markdown/podman-system-df.1.html Maintenance =========== .. code-block:: bash podman image prune -a --filter "until=168h" # One Week podman system prune --all --force # Whipe everything (fresh start, this make take some time, rebuilding the images) podman volume prune --filter "label!=keep" # Remove (currently) unused volumes podman system df -v podman ps --size Copy files to/from container from/to host ========================================= .. code-block:: bash podman cp :/file/path/within/container /host/path/target View "structure" of container images ==================================== .. code-block:: bash podman image history --no-trunc Private-Hub =========== Setup ***** .. code-block:: bash podman run registry To access the Private-Hub without a secure connection (HTTP instead of HTTPS) you need to add an exception for it. To do this, you need to add the ip to the :code:`insecure-registries`. You can do this by editing the file :file:`/etc/docker/daemon.json` .. code-block:: bash { "insecure-registries" : [":5000"] } Alternatively you can make the registry accessable via a reverse proxy with TLS. If you are using you own certificates, you need to add the certs for docker to accept the certificate. Setup with TLS/Certificates: https://docs.docker.com/engine/security/certificates/#troubleshooting-tips .. code-block:: bash /etc/docker/certs.d/ └── my-https.registry.example.com <-- Hostname without port ├── client.cert ├── client.key └── ca.crt Docker-Desktop -------------- Settings → Docker Engine → Add :code:`"insecure-registries" : [":5000"]` on same level as :code:`builder`. Linux ----- Add :code:`"insecure-registries" : [":5000"]` to :code:`daemon.json`. Can be located using :code:`locate`. Publish image on Private-Registry ********************************* .. code-block:: bash podman tag :5000/ podman push :5000/ Action to build and push automatically ************************************** * https://github.com/marketplace/actions/build-and-push-docker-images View Registry Content ********************* * http://:5000/v2/_catalog * http://:5000/v2//tags/list Dockerfile ========== .. note:: `Official Dokumentation `_. Example ******* .. code-block:: bash FROM python:latest # set the working directory WORKDIR /app # install dependencies COPY ./requirements.txt /app RUN pip install --no-cache-dir --upgrade -r requirements.txt # copy the scripts to the folder COPY . /app # start the server CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"] Comments ******** .. code-block:: bash RUN echo 'This one gets printed' # RUN echo 'This one does not' Build and Run in seperat containers *********************************** .. code-block:: bash FROM golang:1-alpine as build WORKDIR /app COPY cmd cmd RUN go build cmd/hello/hello.go FROM alpine:latest WORKDIR /app COPY --from=build /app/hello /app/hello EXPOSE 8180 ENTRYPOINT ["./hello"] Basic Commands ============== Build image from current folder and tag with given name. .. code-block:: bash podman build -t . * :code:`--no-cache` build the image completetly new, takes a lot longer, then building with cache enabled * :code:`--platform` build the image for the specified plattform (*linux/amd64*, *linux/i386*, *linux/arm/v5*, *linux/arm/v6*, *linux/arm/v7*, *linux/arm64*, *linux/ppc64le*, *linux/s390x*) plattform must be available for/in the base image. Run a already build image (my tag name -t) in a container in interactive (-i) mode. .. code-block:: bash podman run -i -t * **-d** (Detached mode) * **-p** (port mapping, could be 8080:80, which would map the port 80 of the container to the port 8080 of the host). * **-rm** (remove conatiner after exit) If you need to *enter* a already running container, check the Container ID with :code:`podman ps` and than run the following command. .. code-block:: bash podman exec -it bash as **root** .. code-block:: bash podman exec -u 0 -it bash Get logs from (stopped/exited) container .. code-block:: bash podman logs -t Use podman-compose to run app with "shared filesystem" (use volumes in docker-compose.yaml file to map a path on the host system with a path in the container) .. code-block:: bash podman-compose run app # or podman-compose up --build Example docker-compose.yaml: .. code-block:: bash services: app: build: . container_name: command: /bin/sh ports: - 8080:80 volumes: - .:/app Command to list all containers, including failed / crashed containers: .. code-block:: bash podman ps -a podman logs podman exec -it bash Run Cron in Container Install ======= If not on a base Ubuntu image, :code:`cat /etc/upstream-release/lsb-release` may give you a result for the release you are on. .. code-block:: bash sudo apt update sudo apt install -y apt-transport-https ca-certificates curl software-properties-common curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt update apt-cache policy docker-ce sudo apt install -y docker-ce sudo systemctl status docker You may want to add your user to the dockre group: :code:`sudo usermod -aG docker $USER` followed by :code:`exec bash -l` and/or :code:`newgrp docker` to take immediate effect. Portainer ========= Update ****** .. code-block:: bash docker stop portainer docker rm portainer docker image rm portainer/portainer-ce docker run -d -p 8000:8000 -p 9000:9000 -p 9443:9443 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest Run Container without immediate exiting *************************************** On container Setup go to :code:`Advanced container settings` and select :code:`Interactive & TTY` (or just TTY) under :code:`Console`. Next check the :code:`Command`, it should read something similar to :code:`/bin/sh` or :code:`/bin/bash` Maintenance =========== .. code-block:: bash podman image prune -a --filter "until=168h" # One Week podman system prune --all --force # Whipe everything (fresh start, this make take some time, rebuilding the images) podman volume prune --filter "label!=keep" # Remove (currently) unused volumes podman system df -v podman ps --size Copy files to/from container from/to host ========================================= .. code-block:: bash podman cp :/file/path/within/container /host/path/target Private-Hub =========== Setup ***** .. code-block:: bash docker run registry To access the Private-Hub without a secure connection (HTTP instead of HTTPS) you need to add an exception for it. To do this, you need to add the ip to the :code:`insecure-registries`. You can do this by editing the file :file:`/etc/docker/daemon.json` .. code-block:: bash { "insecure-registries" : [":5000"] } Alternatively you can make the registry accessable via a reverse proxy with TLS. If you are using you own certificates, you need to add the certs for docker to accept the certificate. Setup with TLS/Certificates: https://docs.docker.com/engine/security/certificates/#troubleshooting-tips .. code-block:: bash /etc/docker/certs.d/ └── my-https.registry.example.com <-- Hostname without port ├── client.cert ├── client.key └── ca.crt Docker-Desktop -------------- Settings → Docker Engine → Add :code:`"insecure-registries" : [":5000"]` on same level as :code:`builder`. Linux ----- Add :code:`"insecure-registries" : [":5000"]` to :code:`daemon.json`. Can be located using :code:`locate`. Publish image on Private-Registry ********************************* .. code-block:: bash docker tag :5000/ docker push :5000/ Action to build and push automatically ************************************** * https://github.com/marketplace/actions/build-and-push-docker-images View Registry Content ********************* * http://:5000/v2/_catalog * http://:5000/v2//tags/list Dockerfile ========== .. note:: `Official Dokumentation `_. Example ******* .. code-block:: bash FROM python:latest # set the working directory WORKDIR /app # install dependencies COPY ./requirements.txt /app RUN pip install --no-cache-dir --upgrade -r requirements.txt # copy the scripts to the folder COPY . /app # start the server CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"] Comments ******** .. code-block:: bash RUN echo 'This one gets printed' # RUN echo 'This one does not' Build and Run in seperat containers *********************************** .. code-block:: bash FROM golang:1-alpine as build WORKDIR /app COPY cmd cmd RUN go build cmd/hello/hello.go FROM alpine:latest WORKDIR /app COPY --from=build /app/hello /app/hello EXPOSE 8180 ENTRYPOINT ["./hello"] Basic Commands ============== Build image from current folder and tag with given name. .. code-block:: bash docker build -t . * :code:`--no-cache` build the image completetly new, takes a lot longer, then building with cache enabled * :code:`--platform` build the image for the specified plattform (*linux/amd64*, *linux/i386*, *linux/arm/v5*, *linux/arm/v6*, *linux/arm/v7*, *linux/arm64*, *linux/ppc64le*, *linux/s390x*) plattform must be available for/in the base image. Run a already build image (my tag name -t) in a container in interactive (-i) mode. .. code-block:: bash docker run -i -t * **-d** (Detached mode) * **-p** (port mapping, could be 8080:80, which would map the port 80 of the container to the port 8080 of the host). * **-rm** (remove conatiner after exit) If you need to *enter* a already running container, check the Container ID with :code:`docker ps` and than run the following command. .. code-block:: bash docker exec -it bash as **root** .. code-block:: bash docker exec -u 0 -it bash Get logs from (stopped/exited) container .. code-block:: bash docker logs -t Use docker-compose to run app with "shared filesystem" (use volumes in docker-compose.yaml file to map a path on the host system with a path in the container) .. code-block:: bash docker-compose run app # or docker-compose up --build Example docker-compose.yaml: .. code-block:: bash services: app: build: . container_name: command: /bin/sh ports: - 8080:80 volumes: - .:/app Command to list all containers, including failed / crashed containers: .. code-block:: bash docker ps -a docker logs docker exec -it bash Run Cron in Container ===================== Create a file with the cron infos: .. code-block:: bash # must be ended with a new line "LF" (Unix) and not "CRLF" (Windows) * * * * * echo "Hello world" >> /var/log/cron.log 2>&1 # An empty line is required at the end of this file for a valid cron file. */5 * * * * /usr/bin/sh /example-scheduled-task.sh Next, change your :code:`Dockerfile` to install cron and register your crontab (example for Debian-based image): .. code-block:: bash RUN apt-get update && apt-get install -y cron COPY example-crontab /etc/cron.d/example-crontab RUN chmod 0644 /etc/cron.d/example-crontab RUN crontab /etc/cron.d/example-crontab If you can not run :code:`ENTRYPOINT ["cron", "-f"]`, because there are other processes that need to be startet, create an :code:`init.sh` and run that instead on startup :code:`ENTRYPOINT ["bash", "init.sh"]`. In the :code:`init.sh` insert the start command for crontab and any furter commands you need. .. code-block:: bash service cron start Dump MySQL Database from Container ================================== If you have the root-password set in an environmental variable (MYSQL_ROOT_PASSWORD) you can simply run the following command. .. code-block:: bash docker exec sh -c 'exec mysqldump --all-databases -uroot -p"$MYSQL_ROOT_PASSWORD"' > /all-databases.sql Mount CIFS within a container ============================= docker run ... \ --cap-add SYS_ADMIN \ --cap-add DAC_READ_SEARCH \ Common Hickups ============== * If you get the Error :code:`init.sh not found`, make sure to use LF instead of CRLF (Linux vs Windows) NGINX Reverse-Proxy =================== * https://github.com/nginx-proxy/nginx-proxy * http://jasonwilder.com/blog/2014/03/25/automated-nginx-reverse-proxy-for-docker/ Usefull Containers ================== * https://github.com/CorentinTh/it-tools * https://greenbone.github.io/docs/latest/22.4/container/index.html Dump MySQL Database from Container ================================== If you have the root-password set in an environmental variable (MYSQL_ROOT_PASSWORD) you can simply run the following command. .. code-block:: bash podman exec sh -c 'exec mysqldump --all-databases -uroot -p"$MYSQL_ROOT_PASSWORD"' > /all-databases.sql Create Multi Architecture Image/Manifest ======================================== .. code-block:: bash podman build --arch=linux/amd64 -t /:v0.1-linux_amd64 . podman build --arch=linux/arm64 -t /:v0.1-linux_arm64 . podman manifest create /:v0.1 /:v0.1-linux_arm64 /:v0.1-linux_amd64 podman manifest push /:v0.1 Mount CIFS within a container ============================= .. code-block:: bash docker run ... \ --cap-add SYS_ADMIN \ --cap-add DAC_READ_SEARCH \ Common Hickups ============== * If you get the Error :code:`init.sh not found`, make sure to use LF instead of CRLF (Linux vs Windows) NGINX Reverse-Proxy =================== * https://github.com/nginx-proxy/nginx-proxy * http://jasonwilder.com/blog/2014/03/25/automated-nginx-reverse-proxy-for-docker/ Usefull Containers ================== * https://github.com/CorentinTh/it-tools * https://greenbone.github.io/docs/latest/22.4/container/index.html