TL;DR: průvodce porovnáváním prostředí pro spouštění aplikací v kontejnerech. Budou zhodnoceny možnosti Dockeru a dalších podobných systémů.

Trocha historie, odkud to všechno pochází
Historie
Prvním známým způsobem izolace aplikací je chroot. Tento systémový příkaz umožňuje změnit kořenový adresář — tímto způsobem poskytuje programu, který ho zavolal, přístup pouze k souborům uvnitř tohoto adresáře. Pokud však programu uvnitř dají práva superuživatele, může potenciálně "utéci" z chrootu a získat přístup k základnímu operačnímu systému. Kromě změny kořenového adresáře nejsou omezeny další prostředky (operační paměť, procesor) ani přístup k síti.
Další metodou je spuštění plnohodnotného operačního systému uvnitř kontejneru pomocí mechanismů jádra operačního systému. V různých operačních systémech se tento způsob nazývá různě, ale podstata je stejná — spuštění několika nezávislých operačních systémů, z nichž každý používá stejné jádro jako základní operační systém. Sem patří FreeBSD Jails, Solaris Zones, OpenVZ a LXC pro Linux. Zajišťuje se izolace nejen podle diskového prostoru, ale i dalších prostředků, konkrétně každý kontejner může mít omezení na procesorový čas, operační paměť a šířku pásma sítě. Ve srovnání s chrootem je těžší dostat se z kontejneru, protože superuživatel v kontejneru má přístup pouze k obsahu kontejneru, nicméně kvůli nutnosti udržovat operační systém uvnitř kontejneru aktuální a používání starších verzí jader (to je aktuální pro Linux, v menší míře pro FreeBSD) je zde nezanedbatelná pravděpodobnost "průniku" systému izolace jádra a získání přístupu k základnímu operačnímu systému.
Místo spuštění plnohodnotného operačního systému v kontejneru (se systémem inicializace, správcem balíků atd.) lze okamžitě spouštět aplikace, hlavní je zajistit aplikacím tuto možnost (přítomnost potřebných knihoven a dalších souborů). Tato myšlenka se stala základem pro kontejnerovou virtualizaci aplikací, jejímž nejjasnějším a nejznámějším zástupcem je Docker. Ve srovnání s předchozími systémy poskytly flexibilnější izolační mechanismy spolu se zabudovanou podporou virtuálních sítí mezi kontejnery a sledováním stavu aplikace uvnitř kontejneru možnost vytvořit jednotné a celistvé prostředí z velkého počtu fyzických serverů pro spuštění kontejnerů — bez nutnosti ručního řízení zdrojů.
Docker
Docker je nejznámější software pro kontejnerizaci aplikací. Napsán v jazyce Go, využívá standardní funkce jádra Linux — cgroups, namespaces, capabilities atd., a také souborové systémy Aufs a další podobné pro úsporu místa na disku.

Zdroj: wikimedia
Architektura
Do verze 1.11 Docker fungoval jako jediná služba, která prováděla všechny operace s kontejnery: stahování obrazů pro kontejnery, spouštění kontejnerů, zpracování API požadavků. S počátkem verze 1.11 byl Docker rozdělen na několik částí, které spolu komunikují: containerd pro správu celého životního cyklu kontejnerů (přidělování diskového prostoru, stahování obrazů, práce se sítí, spouštění, instalace a monitorování stavu kontejnerů) a runC, prostředí pro provádění kontejnerů založené na používání cgroups a dalších funkcí jádra Linux. Samotná služba docker zůstala, ale nyní slouží pouze k zpracování API požadavků, které se přenášejí do containerd.

Instalace a konfigurace
Mým oblíbeným způsobem instalace dockeru je docker-machine, která kromě samotné instalace a nastavení dockeru na vzdálené servery (včetně různých cloudů) umožňuje práci se souborovými systémy vzdálených serverů a také může provádět spouštění různých příkazů.
Od roku 2018 však projekt téměř nevyvíjí, a proto instalaci provedeme běžným způsobem pro většinu distribucí Linux — přidáním repozitáře a instalací potřebných balíků.
Tento způsob se také používá při automatizované instalaci, například pomocí Ansible nebo jiných podobných systémů, ale v tomto článku se tomu nebudu věnovat.
Instalace bude probíhat na Centos 7, jako server použiji virtuální stroj, pro instalaci stačí spustit následující příkazy:
# yum install -y yum-utils
# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# yum install docker-ce docker-ce-cli containerd.ioPo instalaci je nutné spustit službu a přidat ji do automatického spouštění:
# systemctl enable docker
# systemctl start docker
# firewall-cmd --zone=public --add-port=2377/tcp --permanentDále je možné vytvořit skupinu docker, jejíž uživatelé budou moci pracovat s docker bez sudo, nastavit logování, povolit přístup k API zvenčí a nezapomenout podrobněji nastavit firewall (zakázat vše, co není povoleno, v uvedených příkladech jsem to zjednodušil pro přehlednost), ale tomuto se podrobněji věnovat nebudu.
Další možnosti
Kromě výše zmíněné docker machine existuje také docker registry, nástroj pro ukládání obrazů pro kontejnery, a docker compose — nástroj pro automatizaci nasazení aplikací v kontejnerech, používají se soubory YAML pro sestavení a konfiguraci kontejnerů a dalších souvisejících věcí (například sítě, trvalé souborové systémy pro ukládání dat).
Také pomocí něj lze organizovat pipeline pro CICD. Další zajímavou možností je provoz v clusterovém režimu, takzvaném swarm mode (do verze 1.12 známém jako docker swarm), umožňující vytvořit z několika serverů jednotnou infrastrukturu pro spuštění kontejnerů. Existuje podpora virtuální sítě nad všemi servery, je k dispozici vestavěný vyrovnávač zátěže a podpora tajemství pro kontejnery.
Soubory YAML z docker compose s drobnými úpravami mohou být použity pro takové clustery, čímž se plně automatizuje údržba malých a středních clusterů pro různé účely. Pro velké clustry je výhodnější použít Kubernetes, protože náklady na údržbu swarm mode mohou překročit ty s Kubernetes. Kromě runC jako prostředí pro spuštění kontejnerů lze nainstalovat například
Práce s Dockerem
Po instalaci a nastavení se pokusíme vytvořit klastr, ve kterém nasadíme GitLab a Docker Registry pro tým vývojářů. Jako servery použiji tři virtuální stroje, na kterých také nasadím distribuovaný FS GlusterFS, který budu používat jako úložiště docker volumes, například pro spuštění vysoce dostupné verze docker registry. Klíčové komponenty pro spuštění: Docker Registry, Postgresql, Redis, GitLab s podporou GitLab Runner v režimu Swarm. Postgresql spustíme s možností clusterování. , proto pro ukládání dat Postgresql není potřeba používat GlusterFS. Ostatní kritické údaje budou uloženy na GlusterFS.
Pro nasazení GlusterFS na všech serverech (označovaných jako node1, node2, node3) je potřeba nainstalovat balíčky, povolit práci firewallu, vytvořit potřebné adresáře:
# yum -y install centos-release-gluster7
# yum -y install glusterfs-server
# systemctl enable glusterd
# systemctl start glusterd
# firewall-cmd --add-service=glusterfs --permanent
# firewall-cmd --reload
# mkdir -p /srv/gluster
# mkdir -p /srv/docker
# echo "$(hostname):/docker /srv/docker glusterfs defaults,_netdev 0 0" >> /etc/fstabPo instalaci je třeba pokračovat v konfiguraci GlusterFS z jednoho uzlu, například node1:
# gluster peer probe node2
# gluster peer probe node3
# gluster volume create docker replica 3 node1:/srv/gluster node2:/srv/gluster node3:/srv/gluster force
# gluster volume start dockerPoté je třeba připojit získaný volume (příkaz je třeba provést na všech serverech):
# mount /srv/dockerNastavení režimu swarm se provádí na jednom ze serverů, který bude Leader, ostatní se budou muset připojit ke klastru, proto je nutné výsledek provedení příkazu na prvním serveru zkopírovat a provést na ostatních.
První nastavení klastru, příkaz spouštím na node1:
# docker swarm init
Swarm initialized: current node (a5jpfrh5uvo7svzz1ajduokyq) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-0c5mf7mvzc7o7vjk0wngno2dy70xs95tovfxbv4tqt9280toku-863hyosdlzvd76trfptd4xnzd xx.xx.xx.xx:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
# docker swarm join-token managerZkopírujeme výsledek druhého příkazu, provedeme na node2 a node3:
# docker swarm join --token SWMTKN-x-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxx xx.xx.xx.xx:2377
This node joined a swarm as a manager.Na tomto místě je předběžné nastavení serverů ukončeno, přecházíme k nastavování služeb, příkazy budou vykonávány z node1, pokud není uvedeno jinak.
Nejdříve vytvoříme sítě pro kontejnerové aplikace:
# docker network create --driver=overlay etcd
# docker network create --driver=overlay pgsql
# docker network create --driver=overlay redis
# docker network create --driver=overlay traefik
# docker network create --driver=overlay gitlabPoté označíme servery, což je potřeba pro přiřazení některých služeb k serverům:
# docker node update --label-add nodename=node1 node1
# docker node update --label-add nodename=node2 node2
# docker node update --label-add nodename=node3 node3Dále vytváříme adresáře pro ukládání dat etcd, KV úložiště, které je potřeba pro Traefik a Stolon. Podobně jako u Postgresql budou to kontejnery přiřazené k serverům, proto tento příkaz vykonáváme na všech serverech:
# mkdir -p /srv/etcdDále vytvoříme soubor pro nastavení etcd a aplikujeme ho:
00etcd.yml
verze: '3.7'
služby:
etcd1:
obraz: quay.io/coreos/etcd:latest
hostname: etcd1
příkaz:
- etcd
- --name=etcd1
- --data-dir=/data.etcd
- --advertise-client-urls=http://etcd1:2379
- --listen-client-urls=http://0.0.0.0:2379
- --initial-advertise-peer-urls=http://etcd1:2380
- --listen-peer-urls=http://0.0.0.0:2380
- --initial-cluster=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
- --initial-cluster-state=new
- --initial-cluster-token=etcd-cluster
sítě:
- etcd
svazky:
- etcd1vol:/data.etcd
nasazení:
repliky: 1
umístění:
omezení: [node.labels.nodename == node1]
etcd2:
obraz: quay.io/coreos/etcd:latest
hostname: etcd2
příkaz:
- etcd
- --name=etcd2
- --data-dir=/data.etcd
- --advertise-client-urls=http://etcd2:2379
- --listen-client-urls=http://0.0.0.0:2379
- --initial-advertise-peer-urls=http://etcd2:2380
- --listen-peer-urls=http://0.0.0.0:2380
- --initial-cluster=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
- --initial-cluster-state=new
- --initial-cluster-token=etcd-cluster
sítě:
- etcd
svazky:
- etcd2vol:/data.etcd
nasazení:
repliky: 1
umístění:
omezení: [node.labels.nodename == node2]
etcd3:
obraz: quay.io/coreos/etcd:latest
hostname: etcd3
příkaz:
- etcd
- --name=etcd3
- --data-dir=/data.etcd
- --advertise-client-urls=http://etcd3:2379
- --listen-client-urls=http://0.0.0.0:2379
- --initial-advertise-peer-urls=http://etcd3:2380
- --listen-peer-urls=http://0.0.0.0:2380
- --initial-cluster=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
- --initial-cluster-state=new
- --initial-cluster-token=etcd-cluster
sítě:
- etcd
svazky:
- etcd3vol:/data.etcd
nasazení:
repliky: 1
umístění:
omezení: [node.labels.nodename == node3]
svazky:
etcd1vol:
ovladač: local
ovládací možnosti:
typ: none
o: bind
zařízení: "/srv/etcd"
etcd2vol:
ovladač: local
ovládací možnosti:
typ: none
o: bind
zařízení: "/srv/etcd"
etcd3vol:
ovladač: local
ovládací možnosti:
typ: none
o: bind
zařízení: "/srv/etcd"
sítě:
etcd:
externí: true# docker stack deploy --compose-file 00etcd.yml etcdPo chvíli zkontrolujeme, že se cluster etcd spustil:
# docker exec $(docker ps | awk '/etcd/ {print $1}') etcdctl member list
ade526d28b1f92f7: name=etcd1 peerURLs=http://etcd1:2380 clientURLs=http://etcd1:2379 isLeader=false
bd388e7810915853: name=etcd3 peerURLs=http://etcd3:2380 clientURLs=http://etcd3:2379 isLeader=false
d282ac2ce600c1ce: name=etcd2 peerURLs=http://etcd2:2380 clientURLs=http://etcd2:2379 isLeader=true
# docker exec $(docker ps | awk '/etcd/ {print $1}') etcdctl cluster-health
member ade526d28b1f92f7 is healthy: got healthy result from http://etcd1:2379
member bd388e7810915853 is healthy: got healthy result from http://etcd3:2379
member d282ac2ce600c1ce is healthy: got healthy result from http://etcd2:2379
cluster is healthyVytvoříme adresáře pro PostgreSQL, příkaz provedeme na všech serverech:
# mkdir -p /srv/pgsqlDále vytvoříme soubor pro konfiguraci PostgreSQL:
01pgsql.yml
verze: '3.7'
služby:
pgsentinel:
image: sorintlab/stolon:master-pg10
příkaz:
- gosu
- stolon
- stolon-sentinel
- --cluster-name=stolon-cluster
- --store-backend=etcdv3
- --store-endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379
- --log-level=debug
sítě:
- etcd
- pgsql
nasazení:
repliky: 3
aktualizační_config:
paralelismus: 1
zpoždění: 30s
pořadí: stop-first
akcí při chybě: pozastavit
pgkeeper1:
image: sorintlab/stolon:master-pg10
hostname: pgkeeper1
příkaz:
- gosu
- stolon
- stolon-keeper
- --pg-listen-address=pgkeeper1
- --pg-repl-username=replica
- --uid=pgkeeper1
- --pg-su-username=postgres
- --pg-su-passwordfile=/run/secrets/pgsql
- --pg-repl-passwordfile=/run/secrets/pgsql_repl
- --data-dir=/var/lib/postgresql/data
- --cluster-name=stolon-cluster
- --store-backend=etcdv3
- --store-endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379
sítě:
- etcd
- pgsql
prostředí:
- PGDATA=/var/lib/postgresql/data
svazky:
- pgkeeper1:/var/lib/postgresql/data
tajemství:
- pgsql
- pgsql_repl
nasazení:
repliky: 1
umístění:
omezení: [node.labels.nodename == node1]
pgkeeper2:
image: sorintlab/stolon:master-pg10
hostname: pgkeeper2
příkaz:
- gosu
- stolon
- stolon-keeper
- --pg-listen-address=pgkeeper2
- --pg-repl-username=replica
- --uid=pgkeeper2
- --pg-su-username=postgres
- --pg-su-passwordfile=/run/secrets/pgsql
- --pg-repl-passwordfile=/run/secrets/pgsql_repl
- --data-dir=/var/lib/postgresql/data
- --cluster-name=stolon-cluster
- --store-backend=etcdv3
- --store-endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379
sítě:
- etcd
- pgsql
prostředí:
- PGDATA=/var/lib/postgresql/data
svazky:
- pgkeeper2:/var/lib/postgresql/data
tajemství:
- pgsql
- pgsql_repl
nasazení:
repliky: 1
umístění:
omezení: [node.labels.nodename == node2]
pgkeeper3:
image: sorintlab/stolon:master-pg10
hostname: pgkeeper3
příkaz:
- gosu
- stolon
- stolon-keeper
- --pg-listen-address=pgkeeper3
- --pg-repl-username=replica
- --uid=pgkeeper3
- --pg-su-username=postgres
- --pg-su-passwordfile=/run/secrets/pgsql
- --pg-repl-passwordfile=/run/secrets/pgsql_repl
- --data-dir=/var/lib/postgresql/data
- --cluster-name=stolon-cluster
- --store-backend=etcdv3
- --store-endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379
sítě:
- etcd
- pgsql
prostředí:
- PGDATA=/var/lib/postgresql/data
svazky:
- pgkeeper3:/var/lib/postgresql/data
tajemství:
- pgsql
- pgsql_repl
nasazení:
repliky: 1
umístění:
omezení: [node.labels.nodename == node3]
postgresql:
image: sorintlab/stolon:master-pg10
příkaz: gosu stolon stolon-proxy --listen-address 0.0.0.0 --cluster-name stolon-cluster --store-backend=etcdv3 --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379
sítě:
- etcd
- pgsql
nasazení:
repliky: 3
aktualizační_config:
paralelismus: 1
zpoždění: 30s
pořadí: stop-first
akcí při chybě: rollback
svazky:
pgkeeper1:
řidič: local
řidičové_opts:
typ: none
o: bind
zařízení: "/srv/pgsql"
pgkeeper2:
řidič: local
řidičové_opts:
typ: none
o: bind
zařízení: "/srv/pgsql"
pgkeeper3:
řidič: local
řidičové_opts:
typ: none
o: bind
zařízení: "/srv/pgsql"
tajemství:
pgsql:
soubor: "/srv/docker/postgres"
pgsql_repl:
soubor: "/srv/docker/replica"
sítě:
etcd:
externí: true
pgsql:
externí: trueGenerujeme tajemství, použijeme soubor:
# </dev/urandom tr -dc 234567890qwertyuopasdfghjkzxcvbnmQWERTYUPASDFGHKLZXCVBNM | head -c $(((RANDOM%3)+15)) > /srv/docker/replica
# </dev/urandom tr -dc 234567890qwertyuopasdfghjkzxcvbnmQWERTYUPASDFGHKLZXCVBNM | head -c $(((RANDOM%3)+15)) > /srv/docker/postgres
# docker stack deploy --compose-file 01pgsql.yml pgsqlPo nějaké době (sledujeme výstup příkazu docker service ls, co byly všechny služby spuštěny) inicializujeme cluster Postgresql:
# docker exec $(docker ps | awk '/pgkeeper/ {print $1}') stolonctl --cluster-name=stolon-cluster --store-backend=etcdv3 --store-endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 initKontrolujeme připravenost clusteru PostgreSQL:
# docker exec $(docker ps | awk '/pgkeeper/ {print $1}') stolonctl --cluster-name=stolon-cluster --store-backend=etcdv3 --store-endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 status
=== Active sentinels ===
ID LEADER
26baa11d false
74e98768 false
a8cb002b true
=== Active proxies ===
ID
4d233826
9f562f3b
b0c79ff1
=== Keepers ===
UID HEALTHY PG LISTENADDRESS PG HEALTHY PG WANTEDGENERATION PG CURRENTGENERATION
pgkeeper1 true pgkeeper1:5432 true 2 2
pgkeeper2 true pgkeeper2:5432 true 2 2
pgkeeper3 true pgkeeper3:5432 true 3 3
=== Cluster Info ===
Master Keeper: pgkeeper3
===== Keepers/DB tree =====
pgkeeper3 (master)
├─pgkeeper2
└─pgkeeper1
Nastavujeme traefik pro otevření přístupu k kontejnerům zvenčí:
03traefik.yml
verze: '3.7'
služby:
traefik:
obraz: traefik:latest
příkaz: >
--log.level=INFO
--providers.docker=true
--entryPoints.web.address=:80
--providers.providersThrottleDuration=2
--providers.docker.watch=true
--providers.docker.swarmMode=true
--providers.docker.swarmModeRefreshSeconds=15s
--providers.docker.exposedbydefault=false
--accessLog.bufferingSize=0
--api=true
--api.dashboard=true
--api.insecure=true
sítě:
- traefik
porty:
- 80:80
objemy:
- /var/run/docker.sock:/var/run/docker.sock
nasazení:
repliky: 3
umístění:
omezení:
- node.role == manager
preference:
- rozptýlení: node.id
štítky:
- traefik.enable=true
- traefik.http.routers.traefik.rule=Host(`traefik.example.com`)
- traefik.http.services.traefik.loadbalancer.server.port=8080
- traefik.docker.network=traefik
sítě:
traefik:
externí: true# docker stack deploy --compose-file 03traefik.yml traefikSpouštíme Redis Cluster, proto na všech uzlech vytváříme adresář pro úschovu:
# mkdir -p /srv/redis05redis.yml
verze: '3.7'
služby:
redis-master:
obraz: 'bitnami/redis:latest'
sítě:
- redis
porty:
- '6379:6379'
proměnné prostředí:
- REDIS_REPLICATION_MODE=master
- REDIS_PASSWORD=xxxxxxxxxxx
nasazení:
režim: globální
restart_politika:
podmínka: jakýkoli
objemy:
- 'redis:/opt/bitnami/redis/etc/'
redis-replica:
obraz: 'bitnami/redis:latest'
sítě:
- redis
porty:
- '6379'
závisí_na:
- redis-master
proměnné prostředí:
- REDIS_REPLICATION_MODE=slave
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_PASSWORD=xxxxxxxxxxx
- REDIS_PASSWORD=xxxxxxxxxxx
nasazení:
režim: replikovaný
repliky: 3
update_config:
paralelismus: 1
zpoždění: 10s
restart_politika:
podmínka: jakýkoli
redis-sentinel:
obraz: 'bitnami/redis:latest'
sítě:
- redis
porty:
- '16379'
závisí_na:
- redis-master
- redis-replica
vstupní_bod: |
bash -c 'bash -s <<EOF
"/bin/bash" -c "cat < /opt/bitnami/redis/etc/sentinel.conf
port 16379
dir /tmp
sentinel monitor master-node redis-master 6379 2
sentinel down-after-milliseconds master-node 5000
sentinel parallel-syncs master-node 1
sentinel failover-timeout master-node 5000
sentinel auth-pass master-node xxxxxxxxxxx
sentinel announce-ip redis-sentinel
sentinel announce-port 16379
EOF"
"/bin/bash" -c "redis-sentinel /opt/bitnami/redis/etc/sentinel.conf"
EOF'
nasazení:
režim: globální
restart_politika:
podmínka: jakýkoli
objemy:
redis:
ovladač: místní
ovladač_opce:
typ: 'none'
o: 'bind'
zařízení: "/srv/redis"
sítě:
redis:
externí: true# docker stack deploy --compose-file 05redis.yml redisPřidáváme Docker Registry:
06registry.yml
verze: '3.7'
služby:
registry:
obraz: registry:2.6
sítě:
- traefik
svazky:
- registry_data: /var/lib/registry
nasazení:
repliky: 1
umístění:
omezení: [node.role == manager]
restart_policy:
podmínka: on-failure
štítky:
- traefik.enable=true
- traefik.http.routers.registry.rule=Host(`registry.example.com`)
- traefik.http.services.registry.loadbalancer.server.port=5000
- traefik.docker.network=traefik
svazky:
registry_data:
ovladač: local
ovládací možnosti:
typ: none
o: bind
zařízení: "/srv/docker/registry"
sítě:
traefik:
externí: true# mkdir /srv/docker/registry
# docker stack deploy --compose-file 06registry.yml registryA nakonec — GitLab:
08gitlab-runner.yml
verze: '3.7'
služby:
gitlab:
obraz: gitlab/gitlab-ce:latest
sítě:
- pgsql
- redis
- traefik
- gitlab
porty:
- 22222:22
prostředí:
GITLAB_OMNIBUS_CONFIG: |
postgresql['enable'] = false
redis['enable'] = false
gitlab_rails['registry_enabled'] = false
gitlab_rails['db_username'] = "gitlab"
gitlab_rails['db_password'] = "XXXXXXXXXXX"
gitlab_rails['db_host'] = "postgresql"
gitlab_rails['db_port'] = "5432"
gitlab_rails['db_database'] = "gitlab"
gitlab_rails['db_adapter'] = 'postgresql'
gitlab_rails['db_encoding'] = 'utf8'
gitlab_rails['redis_host'] = 'redis-master'
gitlab_rails['redis_port'] = '6379'
gitlab_rails['redis_password'] = 'xxxxxxxxxxx'
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.yandex.ru"
gitlab_rails['smtp_port'] = 465
gitlab_rails['smtp_user_name'] = "noreply@example.com"
gitlab_rails['smtp_password'] = "xxxxxxxxx"
gitlab_rails['smtp_domain'] = "example.com"
gitlab_rails['gitlab_email_from'] = 'noreply@example.com'
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_tls'] = true
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_openssl_verify_mode'] = 'peer'
external_url 'http://gitlab.example.com/'
gitlab_rails['gitlab_shell_ssh_port'] = 22222
svazky:
- gitlab_conf:/etc/gitlab
- gitlab_logs:/var/log/gitlab
- gitlab_data:/var/opt/gitlab
nasazení:
mód: replikovaný
repliky: 1
umístění:
omezení:
- node.role == manager
štítky:
- traefik.enable=true
- traefik.http.routers.gitlab.rule=Host(`gitlab.example.com`)
- traefik.http.services.gitlab.loadbalancer.server.port=80
- traefik.docker.network=traefik
gitlab-runner:
obraz: gitlab/gitlab-runner:latest
sítě:
- gitlab
svazky:
- gitlab_runner_conf:/etc/gitlab
- /var/run/docker.sock:/var/run/docker.sock
nasazení:
mód: replikovaný
repliky: 1
umístění:
omezení:
- node.role == manager
svazky:
gitlab_conf:
ovladač: local
ovládací možnosti:
typ: none
o: bind
zařízení: "/srv/docker/gitlab/conf"
gitlab_logs:
ovladač: local
ovládací možnosti:
typ: none
o: bind
zařízení: "/srv/docker/gitlab/logs"
gitlab_data:
ovladač: local
ovládací možnosti:
typ: none
o: bind
zařízení: "/srv/docker/gitlab/data"
gitlab_runner_conf:
ovladač: local
ovládací možnosti:
typ: none
o: bind
zařízení: "/srv/docker/gitlab/runner"
sítě:
pgsql:
externí: true
redis:
externí: true
traefik:
externí: true
gitlab:
externí: true# mkdir -p /srv/docker/gitlab/conf
# mkdir -p /srv/docker/gitlab/logs
# mkdir -p /srv/docker/gitlab/data
# mkdir -p /srv/docker/gitlab/runner
# docker stack deploy --compose-file 08gitlab-runner.yml gitlabKonečný stav klastru a služeb:
# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
lef9n3m92buq etcd_etcd1 replicated 1/1 quay.io/coreos/etcd:latest
ij6uyyo792x5 etcd_etcd2 replicated 1/1 quay.io/coreos/etcd:latest
fqttqpjgp6pp etcd_etcd3 replicated 1/1 quay.io/coreos/etcd:latest
hq5iyga28w33 gitlab_gitlab replicated 1/1 gitlab/gitlab-ce:latest *:22222->22/tcp
dt7s6vs0q4qc gitlab_gitlab-runner replicated 1/1 gitlab/gitlab-runner:latest
k7uoezno0h9n pgsql_pgkeeper1 replicated 1/1 sorintlab/stolon:master-pg10
cnrwul4r4nse pgsql_pgkeeper2 replicated 1/1 sorintlab/stolon:master-pg10
frflfnpty7tr pgsql_pgkeeper3 replicated 1/1 sorintlab/stolon:master-pg10
x7pqqchi52kq pgsql_pgsentinel replicated 3/3 sorintlab/stolon:master-pg10
mwu2wl8fti4r pgsql_postgresql replicated 3/3 sorintlab/stolon:master-pg10
9hkbe2vksbzb redis_redis-master global 3/3 bitnami/redis:latest *:6379->6379/tcp
l88zn8cla7dc redis_redis-replica replicated 3/3 bitnami/redis:latest *:30003->6379/tcp
1utp309xfmsy redis_redis-sentinel global 3/3 bitnami/redis:latest *:30002->16379/tcp
oteb824ylhyp registry_registry replicated 1/1 registry:2.6
qovrah8nzzu8 traefik_traefik replicated 3/3 traefik:latest *:80->80/tcp, *:443->443/tcpCo lze ještě zlepšit? Určitě je potřeba nastavit v Traefiku fungování kontejnerů přes https, přidat šifrování tls pro PostgreSQL a Redis. Ale celkově už lze předat vývojářům jako PoC. Podíváme se nyní na alternativy Dockeru.
Podman
Další známý engine pro spouštění kontejnerů, uspořádaných do podů (pods, skupiny kontejnerů nasazených společně). Na rozdíl od Dockeru nevyžaduje žádnou službu pro spouštění kontejnerů, veškerá práce probíhá prostřednictvím knihovny libpod. Také je napsán v jazyce Go a potřebuje runtime kompatibilní s OCI pro spuštění kontejnerů, například runC.

Práce s Podmanem celkově připomíná práci s Dockerem, až tolik, že lze udělat takto (tvrdí mnozí, kteří to zkusili, včetně autora tohoto článku):
$ alias docker=podmana lze pokračovat v práci. Celkově je situace s Podmanem velmi zajímavá, neboť pokud dřívější verze Kubernetes pracovaly s Dockerem, od přibližně roku 2015, po standardizaci kontejnérů (OCI - Open Container Initiative) a rozdělení Dockeru na containerd a runC, se vyvíjí alternativa Dockeru pro spuštění v Kubernetes: CRI-O. Podman je v tomto ohledu alternativou Dockeru, založenou na principech Kubernetes, včetně seskupování kontejnerů, ale hlavním cílem existence projektu je spouštění kontejnerů v stylu Docker bez dalších služeb. Z pochopitelných důvodů zde není swarm mode, protože vývojáři jasně říkají, že pokud potřebujete klastr — vezměte Kubernetes.
Instalace
Pro instalaci v CentOS 7 stačí aktivovat repozitář Extras, poté nainstalovat vše příkazem:
# yum -y install podmanDalší možnosti
Podman může generovat jednotky pro systemd, tímto způsobem řeší úkol spouštění kontejnerů po restartu serveru. Dále je uvedena správná funkce systemd jako pid 1 v kontejneru. Pro sestavování kontejnerů existuje samostatný nástroj buildah, jsou zde také obdobné nástroje — jako docker-compose, generující mimo jiné konfigurační soubory kompatibilní s Kubernetes, což usnadňuje přechod z Podman na Kubernetes, jak jen to je možné.
Práce s Podmanem
Protože zde není swarm mode (předpokládá se přechod na Kubernetes, pokud je potřeba klastr) — budeme sestavovat jednotlivé kontejnery.
Instalujeme podman-compose:
# yum -y install python3-pip
# pip3 install podman-composeVýsledný konfigurační soubor pro podman se mírně liší, například bylo nutné přesunout jednotlivou sekci volumes přímo do sekce se službami.
gitlab-podman.yml
verze: '3.7'
služby:
gitlab:
obrázek: gitlab/gitlab-ce:latest
hostname: gitlab.example.com
restart: unless-stopped
environment:
GITLAB_OMNIBUS_CONFIG: |
gitlab_rails['gitlab_shell_ssh_port'] = 22222
ports:
- "80:80"
- "22222:22"
volumes:
- /srv/podman/gitlab/conf:/etc/gitlab
- /srv/podman/gitlab/data:/var/opt/gitlab
- /srv/podman/gitlab/logs:/var/log/gitlab
networks:
- gitlab
gitlab-runner:
obrázek: gitlab/gitlab-runner:alpine
restart: unless-stopped
depends_on:
- gitlab
volumes:
- /srv/podman/gitlab/runner:/etc/gitlab-runner
- /var/run/docker.sock:/var/run/docker.sock
networks:
- gitlab
sítě:
gitlab:# podman-compose -f gitlab-runner.yml -d upVýsledek práce:
# podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
da53da946c01 docker.io/gitlab/gitlab-runner:alpine run --user=gitlab... About a minute ago Up About a minute ago 0.0.0.0:22222->22/tcp, 0.0.0.0:80->80/tcp root_gitlab-runner_1
781c0103c94a docker.io/gitlab/gitlab-ce:latest /assets/wrapper About a minute ago Up About a minute ago 0.0.0.0:22222->22/tcp, 0.0.0.0:80->80/tcp root_gitlab_1Podívejme se, co vygeneruje pro systemd a kubernetes, k tomu je potřeba zjistit název nebo ID podu:
# podman pod ls
POD ID NAME STATUS CREATED # OF CONTAINERS INFRA ID
71fc2b2a5c63 root Running 11 minutes ago 3 db40ab8bf84bKubernetes:
# podman generate kube 71fc2b2a5c63
# Generation of Kubernetes YAML is still under development!
#
# Save the output of this file and use kubectl create -f to import
# it into Kubernetes.
#
# Created with podman-1.6.4
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2020-07-29T19:22:40Z"
labels:
app: root
name: root
spec:
containers:
- command:
- /assets/wrapper
env:
- name: PATH
value: /opt/gitlab/embedded/bin:/opt/gitlab/bin:/assets:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- name: TERM
value: xterm
- name: HOSTNAME
value: gitlab.example.com
- name: container
value: podman
- name: GITLAB_OMNIBUS_CONFIG
value: |
gitlab_rails['gitlab_shell_ssh_port'] = 22222
- name: LANG
value: C.UTF-8
image: docker.io/gitlab/gitlab-ce:latest
name: rootgitlab1
ports:
- containerPort: 22
hostPort: 22222
protocol: TCP
- containerPort: 80
hostPort: 80
protocol: TCP
resources: {}
securityContext:
allowPrivilegeEscalation: true
capabilities: {}
privileged: false
readOnlyRootFilesystem: false
volumeMounts:
- mountPath: /var/opt/gitlab
name: srv-podman-gitlab-data
- mountPath: /var/log/gitlab
name: srv-podman-gitlab-logs
- mountPath: /etc/gitlab
name: srv-podman-gitlab-conf
workingDir: /
- command:
- run
- --user=gitlab-runner
- --working-directory=/home/gitlab-runner
env:
- name: PATH
value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- name: TERM
value: xterm
- name: HOSTNAME
- name: container
value: podman
image: docker.io/gitlab/gitlab-runner:alpine
name: rootgitlab-runner1
resources: {}
securityContext:
allowPrivilegeEscalation: true
capabilities: {}
privileged: false
readOnlyRootFilesystem: false
volumeMounts:
- mountPath: /etc/gitlab-runner
name: srv-podman-gitlab-runner
- mountPath: /var/run/docker.sock
name: var-run-docker.sock
workingDir: /
volumes:
- hostPath:
path: /srv/podman/gitlab/runner
type: Directory
name: srv-podman-gitlab-runner
- hostPath:
path: /var/run/docker.sock
type: File
name: var-run-docker.sock
- hostPath:
path: /srv/podman/gitlab/data
type: Directory
name: srv-podman-gitlab-data
- hostPath:
path: /srv/podman/gitlab/logs
type: Directory
name: srv-podman-gitlab-logs
- hostPath:
path: /srv/podman/gitlab/conf
type: Directory
name: srv-podman-gitlab-conf
status: {}Systemd:
# podman generate systemd 71fc2b2a5c63
# pod-71fc2b2a5c6346f0c1c86a2dc45dbe78fa192ea02aac001eb8347ccb8c043c26.service
# autogenerated by Podman 1.6.4
# Thu Jul 29 15:23:28 EDT 2020
[Unit]
Description=Podman pod-71fc2b2a5c6346f0c1c86a2dc45dbe78fa192ea02aac001eb8347ccb8c043c26.service
Documentation=man:podman-generate-systemd(1)
Requires=container-781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3.service container-da53da946c01449f500aa5296d9ea6376f751948b17ca164df438b7df6607864.service
Before=container-781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3.service container-da53da946c01449f500aa5296d9ea6376f751948b17ca164df438b7df6607864.service
[Service]
Restart=on-failure
ExecStart=/usr/bin/podman start db40ab8bf84bf35141159c26cb6e256b889c7a98c0418eee3c4aa683c14fccaa
ExecStop=/usr/bin/podman stop -t 10 db40ab8bf84bf35141159c26cb6e256b889c7a98c0418eee3c4aa683c14fccaa
KillMode=none
Type=forking
PIDFile=/var/run/containers/storage/overlay-containers/db40ab8bf84bf35141159c26cb6e256b889c7a98c0418eee3c4aa683c14fccaa/userdata/conmon.pid
[Install]
WantedBy=multi-user.target
# container-da53da946c01449f500aa5296d9ea6376f751948b17ca164df438b7df6607864.service
# autogenerated by Podman 1.6.4
# Thu Jul 29 15:23:28 EDT 2020
[Unit]
Description=Podman container-da53da946c01449f500aa5296d9ea6376f751948b17ca164df438b7df6607864.service
Documentation=man:podman-generate-systemd(1)
RefuseManualStart=yes
RefuseManualStop=yes
BindsTo=pod-71fc2b2a5c6346f0c1c86a2dc45dbe78fa192ea02aac001eb8347ccb8c043c26.service
After=pod-71fc2b2a5c6346f0c1c86a2dc45dbe78fa192ea02aac001eb8347ccb8c043c26.service
[Service]
Restart=on-failure
ExecStart=/usr/bin/podman start da53da946c01449f500aa5296d9ea6376f751948b17ca164df438b7df6607864
ExecStop=/usr/bin/podman stop -t 10 da53da946c01449f500aa5296d9ea6376f751948b17ca164df438b7df6607864
KillMode=none
Type=forking
PIDFile=/var/run/containers/storage/overlay-containers/da53da946c01449f500aa5296d9ea6376f751948b17ca164df438b7df6607864/userdata/conmon.pid
[Install]
WantedBy=multi-user.target
# container-781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3.service
# autogenerated by Podman 1.6.4
# Thu Jul 29 15:23:28 EDT 2020
[Unit]
Description=Podman container-781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3.service
Documentation=man:podman-generate-systemd(1)
RefuseManualStart=yes
RefuseManualStop=yes
BindsTo=pod-71fc2b2a5c6346f0c1c86a2dc45dbe78fa192ea02aac001eb8347ccb8c043c26.service
After=pod-71fc2b2a5c6346f0c1c86a2dc45dbe78fa192ea02aac001eb8347ccb8c043c26.service
[Service]
Restart=on-failure
ExecStart=/usr/bin/podman start 781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3
ExecStop=/usr/bin/podman stop -t 10 781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3
KillMode=none
Type=forking
PIDFile=/var/run/containers/storage/overlay-containers/781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3/userdata/conmon.pid
[Install]
WantedBy=multi-user.targetBohužel kromě spuštění kontejnerů generovaný unit pro systemd nic dalšího nedělá (například úklid starých kontejnerů při restartu takové služby), takže takové věci bude nutné doprogramovat samostatně.
V podstatě je Podman dostatečný k tomu, abyste si vyzkoušeli, co jsou kontejnery, přenést staré konfigurace pro docker-compose, po čemž můžete přejít na Kubernetes, pokud potřebujete na cluster, nebo získat jednodušší alternativu k Dockeru.
rkt
Projekt přibližně před šesti měsíci, protože ho koupil RedHat, proto se na něm nebudu podrobněji zastavovat. Celkově zanechával docela dobrý dojem, ovšem v porovnání s Dockerem a tím více s Podmanem vypadá jako kombajn. Také existoval distribuce CoreOS, postavená na základě rkt (ačkoli původně měli Docker), jehož podpora však také skončila po koupi RedHat.
Plash
Další , jehož autor chtěl prostě sbírat a spouštět kontejnery. Soudě podle dokumentace a kódu – autor nesledoval standardy, ale rozhodl se napsat svou vlastní implementaci, což v zásadě udělal.
Závěry
Situace v přítomnosti Kubernetes je velmi zajímavá: na jedné straně lze s Dockerem sestavit cluster (v módu swarm), se kterým lze dokonce spouštět produktové prostředí pro klienty, což je zejména актуální pro malé týmy (3-5 osob), nebo při malé celkové zátěži, či při absenci chuť se zabývat nuancemi nastavení Kubernetes, včetně vysoké zátěže.
Podman nenabízí plnou kompatibilitu, ale má jednu důležitou výhodu — kompatibilitu s Kubernetes, včetně doplňkových nástrojů (buildah a další). Proto k výběru nástroje pro práci přistoupím takto: pro malé týmy nebo při omezeném rozpočtu — Docker (s možným režimem swarm), pro vývoj na osobním localhost — Podman s kolegy, a pro všechny ostatní — Kubernetes.
Nejsem si jistý, zda se situace s Dockerem v budoucnu nezmění, přeci jen jsou pionýři a také se krok za krokem pomalu standardizují, ale u Podmanu, navzdory všem jeho nedostatkům (funguje pouze na Linuxu, žádná klasterizace, sestavování a další operace — prostřednictvím externích řešení), je budoucnost jasnější, proto zvu všechny zúčastněné k diskuzi těchto závěrů v komentářích.
P.S. 3. srpna spouštíme „“, kde se můžete dozvědět více o jeho fungování. Probereme všechny jeho nástroje: od základních abstrakcí po parametry sítě, nuance práce s různými operačními systémy a programovacími jazyky. Seznámíte se s technologií a pochopíte, kde a jak nejlépe používat Docker. Také se podělíme o best practice případy.
Cena předobjednávky před vydáním: 5000 Kč. S programem „Video kurzu o Dockeru“ se můžete seznámit .
Zdroj: habr.com
