====== Технология Docker ====== * [[https://youtu.be/hdVNKmru3LM|youtube/Проникновение в Docker с примерами, Дмитрий Столяров, Flant]] * [[https://www.upguard.com/articles/docker-vs-lxc|Docker vs LXC]] * [[https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04-ru|Установка и использование Docker в Ubuntu 20.04]] * [[https://youtu.be/QF4ZF857m44|youtube/Артем Матяшов/Основы Docker. Большой практический выпуск]] ===== Методические идеи ===== * Добавить запись в журнал передаваемых скрипту webd заголовков * Использовать переменную окружения, передаваемую контейнеру для включения/выключения режима отладки/записи в журнал ===== Установка ===== ==== Ubuntu ==== * [[https://docs.docker.com/engine/install/ubuntu/|Install Docker Engine on Ubuntu]] # apt install docker.io ==== Debian ==== * [[https://docs.docker.com/engine/installation/linux/docker-ce/debian/|Get Docker CE for Debian]] === Debian 10 === # apt install ca-certificates curl gnupg lsb-release # curl -fsSL https://download.docker.com/linux/debian/gpg | 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/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list # apt update # apt install docker-ce docker-ce-cli containerd.io ==== Тестирование установки ==== # systemctl status docker # docker info # docker run hello-world ==== Предоставление прав непривилегированным пользователям ==== # usermod -aG docker gitlab-runner # su - gitlab-runner ===== Работа с образами и контейнерами ===== * [[https://www.baeldung.com/ops/docker-image-layers-sizes|Finding the Layers and Layer Sizes for a Docker Image]] * [[https://docs.docker.com/engine/reference/commandline/system_prune/|docker system prune - Remove unused data]] * [[Сервис Grafana]] ==== Обзор и удаление ==== # docker images # docker ps -a # docker container ls -a # docker start -i NNNNNNNNNNN # docker rm $(docker ps -aq) # docker rm $(docker ps -q -f status=exited) # docker rmi hello-world # docker rmi -f $(docker images -aq) # docker system prune # docker system prune -a --volumes ==== Копирование файлов в контейнер ==== root@webinar:~# docker cp ca.crt greenlight-v3:/usr/local/share/ca-certificates/ root@webinar:~# docker exec -ti greenlight-v3 /usr/sbin/update-ca-certificates root@webinar:~# docker exec greenlight-v3 wget -O /dev/null https://keycloak.corp13.un root@webinar:~# docker commit greenlight-v3 bigbluebutton/greenlight:v3 ==== Создание контейнера для приложения вручную ==== * !!! каталог и содержимое /var/www создать в хост системе а скрипт webd в контейнере * [[Средства программирования shell#Ресурсы Web сервера на shell]] server# docker run -it --name webd --hostname webd debian bash webd# apt update && apt install file procps nano * [[Сервис INETD]] * [[Средства программирования shell#Web сервер на shell]] webd/# cat start.sh #!/bin/sh /etc/init.d/inetutils-inetd start bash * Ctrl+D server# docker ps -a server# docker diff webd * Методически, "вспомнили", что "забыли" сделать скрипт start.sh "выполнимым" server# docker start webd server# docker attach webd root@webd:/# chmod +x start.sh * Методически, можно уже на этом этапе: запустить скрипт ./start.sh, отключится от контейнера без его остановки Ctrl+P, Q(still holding Ctrl), выяснить через docker inspect webd назначенный контейнеру ip, проверить через curl работу приложения и, если все работает (правда, будет сообщение, что такого файла нет), сделать docker stop webd, и commit * [[https://cpab.ru/kak-rabotajut-tegi-docker-cloudsavvy-it/|Как работают теги Docker?]] * [[https://code.tutsplus.com/ru/tutorials/docker-from-the-ground-up-understanding-images--cms-28165|Докер с нуля: понимание слоев образов]] * Пакет RSYNC - [[Пакет RSYNC#Инкрементное копирование (Incremental Backup)]] server# docker commit webd test/webd gitlab-runner@server:~$ docker images * [[#Запуск в режиме демона и подключение к контейнеру]] из полученного образа ==== Создание контейнера для приложения с использованием Dockerfile ==== * [[Сервис TACACS+]] server# mkdir /root/webd/ && cd /root/webd/ или gitlab-runner@server:~$ mkdir -p ~/webd/webd/ && cd ~/webd/webd/ server# cp /usr/local/sbin/webd . или * [[Средства программирования shell#Web сервер на shell]] gitlab-runner@server:~/webd/webd$ nano webd # добавляем закомментированные строки server# ###tar -cvzf www.tgz -C /var/ www/ server# cat start.sh #!/bin/sh /etc/init.d/inetutils-inetd start touch /var/log/webd.log #chown 10003 /var/www/ if [ "$MYMODE" = 'TEST' ]; then bash # not work in k8s else tail -f /var/log/webd.log fi server# cat Dockerfile #FROM debian:buster FROM debian:bullseye RUN cp /usr/share/zoneinfo/Etc/GMT-3 /etc/localtime \ && apt-get update \ && apt-get install -y inetutils-inetd file \ && apt-get clean \ && echo 'www stream tcp nowait root /usr/local/sbin/webd webd' > /etc/inetd.conf COPY start.sh / COPY webd /usr/local/sbin/webd ### ADD www.tgz /var/ ### for helm readiness/liveness Probe ### COPY index.html /var/www/ EXPOSE 80 #ENV MYMODE=TEST ENTRYPOINT ["/start.sh"] # docker build -t test/webd . # docker history test/webd === Dockerfile Multistage Building === * [[Язык программирования Golang]] * [[https://habr.com/ru/articles/647255/|Рекомендации по работе с Docker для Golang-разработчиков (Multistage Building)]] * [[https://www.docker.com/blog/containerize-your-go-developer-environment-part-2/|Containerize Your Go Developer Environment – Part 2]] student@client1:~/gowebd$ cat Dockerfile FROM golang #FROM golang as builder WORKDIR /build COPY . . RUN test -e go.mod || go mod init gowebd #ENV CGO_ENABLED=0 RUN go build -o /gowebd #FROM alpine #COPY --from=builder /gowebd /gowebd ENTRYPOINT ["/gowebd"] student@client1:~/gowebd$ docker images student@client1:~/gowebd$ time docker build -t gowebd . real 6m2.564s student@client1:~/gowebd$ docker run -d -p 8080:80 --rm gowebd ==== Запуск в режиме демона и подключение к контейнеру ==== 1-й пример - запуск образа сделанного "вручную", можно запустить несколько экземпляров с -p 80 выяснить назначенные порты, настроить keepalived и провести нагрузочное тестирование server# docker run --name webd01 --hostname webd01 -itd -v /var/www/:/var/www/ -p 8000:80 test/webd /start.sh 2-й пример - через Dockerfile задан entrypoint и expose, ключ --rm для удаления контейнера после остановки, добавить, при необходимости, -v server# docker run --name webd01 -e MYMODE=TEST -itd --rm -P test/webd 3-й раз - запустить несколько экземпляров, указав параметры для подключения внешнего каталога /var/www/, выяснить назначенные порты, настроить keepalived, по журналам определять какой контейнер используется === Процессы контейнера и системы === * [[Технология cgroup]] * [[Технология namespaces]] server# docker top webd01 server# ps axw | grep inetd server# ps axw | grep start.sh server# cat /proc//cgroup server# systemd-cgls server# cat /sys/fs/cgroup/memory/docker/NNNNNNNNNNNNNNNNNNNNNNNNNNNNN/memory.max_usage_in_bytes server# docker stats server# lsns | grep start.sh === Анализ параметров запущенного контейнера === server# docker inspect webd01 server# docker inspect webd01 -f {{.NetworkSettings.IPAddress}} server# wget -qO - http://172.17.0.2/ server$ curl --noproxy '*' http://172.17.0.2/ server# docker port webd01 server# docker logs webd01 node1# docker logs webd01 -f server# wget -qO - http://localhost:8000/ server$ curl http://localhost:8000 server$ curl http://localhost:8000/not_exit_file host browser -> http://server.corpX.un:8000/ server# docker attach webd01 server# docker exec -it webd01 bash webd01# ps ax или webd01# ls /proc/ webd01# cat /proc/1/cmdline webd01# ss -tpan или webd01# cat /proc/net/tcp webd01# cat /proc/net/tcp6 Ctrl+P, Q(still holding Ctrl) server# docker stop webd01 server# docker inspect webd01 server# docker start webd01 host browser -> http://server.corpX.un:8000/ server# docker stop webd01 && docker rm webd01 ==== Микросервисы ==== * [[https://hub.docker.com/search?type=image|Explore Docker's Container Image Repository]] * [[https://hub.docker.com/r/atmoz/sftp|atmoz/sftp]] # docker search sftp # chown -R 10003 /var/www # docker run --name sftp01 -v /var/www:/home/user3/www -p 2222:22 -d atmoz/sftp user3:password3:10003 # docker exec -it sftp01 bash Ctrl+D # docker top sftp01 # sftp -P 2222 user3@localhost * [[Сервис SSH#Настройка ssh клиента]] # docker logs sftp01 # docker stop sftp01 ===== docker-compose ===== * [[https://habr.com/ru/company/ruvds/blog/450312/|Руководство по Docker Compose для начинающих]] * [[https://stackoverflow.com/questions/39663096/docker-compose-creating-multiple-instances-for-the-same-image|docker-compose creating multiple instances for the same image]] * [[Инструмент GitLab#Установка через docker-compose]] GitLab * Установка через [[Сервис Keycloak#docker-compose]] Keycloak # apt install docker-compose debian11# service docker start # cat docker-compose.yml version: "3" services: webd: image: test/webd build: webd/ ports: - "8000:80" # - "80" volumes: - /var/www/:/var/www/ # - vol1:/var/www/ # environment: # - MYMODE=TEST # stdin_open: true tty: true sftp: image: atmoz/sftp ports: - "2222:22" volumes: - /var/www/:/home/user3/www # - vol1:/home/user3/www command: user3:password3:10003 #volumes: # vol1: # docker-compose build # docker-compose up -d # docker-compose stop # docker-compose start # docker-compose down # docker-compose rm # docker volume rm root_vol1 gitlab-runner@server:~/webd$ docker-compose up -d --scale webd=N gitlab-runner@server:~/webd$ docker ps gitlab-runner@server:~/webd$ docker-compose down gitlab-runner@server:~/webd$ cat docker-compose.yml version: "3" services: webd: image: server.corpX.un:5000/student/webd:ver1.N ports: - "80" volumes: - /var/www/:/var/www/ deploy: mode: replicated replicas: 3 node1,2,3# docker-compose --compatibility up -d node1,2,3# docker-compose --compatibility down node1,2,3# docker ps -q | xargs -l docker port | sort -n ===== Локальные репозитории ===== ==== Insecure Private Registry ==== * [[Инструмент GitLab#GitLab Docker Registry]] * [[https://docs.docker.com/registry/insecure/|Test an insecure registry/Deploy a plain HTTP registry]] # cat /etc/docker/daemon.json { "insecure-registries" : ["server.corpX.un:5000"] } # service docker restart gitlab-runner@server:~$ docker login http://server.corpX.un:5000 gitlab-runner@server:~$ less ~/.docker/config.json { "auths": { "server.corpX.un:5000": { "auth": "c3R1ZGVudDpQYSQkdzByZA==" } } } * [[https://serverfault.com/questions/703344/how-to-remove-an-image-tag-in-docker-without-removing-the-image-itself|How to remove an image tag in Docker without removing the image itself?]] gitlab-runner@server:~$ docker images gitlab-runner@server:~$ docker tag test/webd server.corpX.un:5000/student/webd gitlab-runner@server:~$ docker tag test/webd server.corpX.un:5000/student/webd:1.1 gitlab-runner@server:~$ docker images gitlab-runner@server:~$ docker push server.corpX.un:5000/student/webd gitlab-runner@server:~$ docker push server.corpX.un:5000/student/webd:1.1 ... node1_2_3# docker run --name webd01 --hostname webd01 -itd --rm -p 8000:80 server.corpX.un:5000/student/webd node1_2_3# docker run --name webd0N --hostname webd0N -itd --rm -P -v /var/www/:/var/www/ server.corpX.un:5000/student/webd ==== Secure Private Registry ==== * [[Пакет OpenSSL#Импорт сертификата центра сертификации]] # docker pull server.corp13.un:5050/student/gowebd # docker login server.corp13.un:5050 ==== Использование образа Docker Registry и on-premise CA ==== * [[https://docs.docker.com/registry/|Docker Registry]] gate# docker run -d -p 5000:5000 -v /root:/certs -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/gate.crt -e REGISTRY_HTTP_TLS_KEY=/certs/gate.key --name registry registry:2 node1# cp ~vagrant/gate.crt /etc/docker/certs.d/gate.corp13.un\:5000/ca.crt node1# service docker restart node1# docker tag val/webd:latest gate.corp13.un:5000/webd node1# docker push gate.corp13.un:5000/webd node1# curl --insecure -X GET https://gate.corp13.un:5000/v2/_catalog {"repositories":["webd"]} val@gitlab-vkube:~$ curl -s https://gitlab-vkube.bmstu.ru:5000/v2/postgresql/tags/list | jq { "name": "postgresql", "tags": [ "13" ] } ===== Дополнительная информация ===== ==== Приложение apwebd ==== ~/apwebd$ cat Dockerfile FROM debian:bookworm RUN cp /usr/share/zoneinfo/Etc/GMT-3 /etc/localtime \ && apt-get update \ && apt-get install -y findutils gettext-base apache2 libapache2-mod-auth-openidc \ && apt-get clean \ && a2enmod cgid \ && a2enmod auth_openidc COPY rootfs/ / EXPOSE 80 ENTRYPOINT ["/start.sh"] ~/apwebd$ find rootfs/ -type f | xargs tail -n +1 ==> rootfs/var/www/html/index.html.apwebd-template <==

Login to ${APWEBD_HOSTNAME}

Version: 1.2
==> rootfs/start.sh <== #!/bin/sh [ "$APWEBD_HOSTNAME" ] || { echo Please set env APWEBD_HOSTNAME; exit; } [ "$KEYCLOAK_HOSTNAME" ] || { echo Please set env KEYCLOAK_HOSTNAME; exit; } [ "$REALM_NAME" ] || { echo Please set env REALM_HOSTNAME; exit; } find / -type f -name '*.apwebd-template' | while read -r FILE; do envsubst < "$FILE" > "${FILE%.apwebd-template}"; done /etc/init.d/apache2 start tail -f /var/log/apache2/error.log -f /var/log/apache2/access.log ==> rootfs/etc/apache2/conf-available/serve-cgi-bin.conf.apwebd-template <== Define ENABLE_USR_LIB_CGI_BIN Define ENABLE_USR_LIB_CGI_BIN OIDCSSLValidateServer Off OIDCProviderMetadataURL https://${KEYCLOAK_HOSTNAME}/realms/${REALM_NAME}/.well-known/openid-configuration OIDCRedirectURI http://${APWEBD_HOSTNAME}/cgi-bin/apwebd OIDCClientID any-client OIDCCryptoPassphrase anystring ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch # Require all granted AuthType openid-connect Require valid-user ==> rootfs/usr/lib/cgi-bin/apwebd <== #!/bin/sh echo Content-type: text/html echo echo "

Hello ${OIDC_CLAIM_preferred_username}

" echo "
"; env; echo "
"
~/apwebd$ docker build -t server.corp13.un:5000/student/apwebd:ver1.2 . ~/apwebd$ docker run -e APWEBD_HOSTNAME=apwebd.corp13.un -e KEYCLOAK_HOSTNAME=keycloak.corp13.un -e REALM_NAME=corp13 -itd --rm -P server.corp13.un:5000/student/apwebd:ver1.2 ~/apwebd$ docker run -e APWEBD_HOSTNAME=apwebd.corp13.un -e KEYCLOAK_HOSTNAME=keycloak.corp13.un -e REALM_NAME=corp13 -itd --entrypoint bash server.corp13.un:5000/student/apwebd:ver1.2 ~/apwebd$ docker push server.corp13.un:5000/student/apwebd:ver1.2 ===== Старая версия ===== ==== Работа с образами ==== * [[https://hub.docker.com/|Docker Hub]] # docker search debian # docker pull debian # docker images # docker commit debian_cont_01 debian_img_01 # docker rmi debian_img_01 ==== Работа с контейнерами ==== * ключи -i -t необходимы для возможности интерактивно (attach) подключаться к запущенному контейнеру # docker create -i -t --name debian_cont_01 debian # docker ps -a # docker container ls -a # docker update --restart=always debian_cont_01 # docker start debian_cont_01 # docker ps # docker container ls # docker inspect debian_cont_01 # docker top debian_cont_01 # docker attach debian_cont_01 :/# apt update :/# apt install iputils-ping :/# ping -c1 ya.ru Ctrl+P, Q(still holding Ctrl) # docker stop debian_cont_01 # docker rm debian_cont_01 # docker rm $(docker ps -aq) ==== Работа с сетью ==== === Управление сетями === # docker network ls # docker network create --subnet=192.168.200+X.0/24 corpX_dmz # docker run -h mail.corpX.un --net corpX_dmz --ip 192.168.200+X.10 -i -t --name debian_cont_01 debian # docker network inspect corpX_dmz === Назначение публичного ip для контейнера === == Вариант 1 == Использование bridge * [[https://jpetazzo.github.io/2013/10/16/configure-docker-bridge-network/|How to configure Docker to start containers on a specific IP address range]] == Вариант 2 == Использование nat/dnat * [[http://stackoverflow.com/questions/27937185/assign-static-ip-to-docker-container|Assign static IP to Docker container]] * присваиваем публичные ip адреса интерфейсу host машины и настраиваем NAT/DNAT связывающие публичные ip host машины со статическими ip контейнеров # ip addr add 172.16.1.100+X dev eth2 # iptables -t nat -A POSTROUTING -o eth2 -s 192.168.100+X.10 -j SNAT --to-source 172.16.1.100+X # iptables -t nat -A PREROUTING -i eth2 --destination 172.16.1.100+X -j DNAT --to-destination 192.168.100+X.10 ==== HEARTBEAT и Docker ==== nodeN# cat haresources node1.corpX.un drbddisk Filesystem::/dev/drbd0::/disk2::ext4 docker