====== Технология 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 <==
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