TL;DR: prehľadový článok-vedenie na porovnanie prostredí pre spúšťanie aplikácií v kontajneroch. Budú preskúmané možnosti Dockeru a iných podobných systémov.

Trocha histórie, odkiaľ to všetko pochádza
História
Prvým verejne známym spôsobom izolácie aplikácie je chroot. Rovnomenný systémový volanie zabezpečuje zmenu koreňového adresára — týmto spôsobom zabezpečuje prístup programu, ktorý ho vyvolal, len k súborom vo vnútri tohto adresára. Ak však programu vo vnútri poskytneme práva superužívateľa, potenciálne môže 'uteč' z chrootu a získať prístup k základnému operačnému systému. Okrem zmeny koreňového adresára nie sú obmedzené ani iné zdroje (operačná pamäť, procesor), ako aj prístup k sieti.
Ďalším spôsobom je spustenie celého operačného systému vo vnútri kontajnera, vďaka mechanizmom jadra operačného systému. V rôznych operačných systémoch sa tento spôsob nazýva rôzne, ale podstata je rovnaká — spustenie niekoľkých nezávislých operačných systémov, z ktorých každý pracuje s tým istým jadrom, na ktorom pracuje aj základný operačný systém. Toto zahŕňa FreeBSD Jails, Solaris Zones, OpenVZ a LXC pre Linux. Zabezpečuje sa izolácia nielen po diskovom priestore, ale aj ostatných zdrojoch, pričom každý kontajner môže mať obmedzenia na procesorový čas, operačnú pamäť, priepustnosť siete. V porovnaní s chrootom je ťažšie uniknúť z kontajnera, keďže superužívateľ v kontajneri má prístup iba k obsahu kontajnera, avšak z dôvodu potreby udržiavať operačný systém vo vnútri kontajnera aktuálny a používania starých verzií jadier (aktuálne pre Linux, menej pre FreeBSD) existuje nenulová pravdepodobnosť 'prerazenia' systému izolácie jadra a získania prístupu k základnému operačnému systému.
Namiesto spustenia plnohodnotného operačného systému v kontajneri (so systémom inicializácie, správcom balíčkov a pod.) je možné okamžite spustiť aplikácie, pričom je dôležité zabezpečiť aplikáciám potrebné podmienky (prítomnosť potrebných knižníc a iných súborov). Táto myšlienka slúžila ako základ pre kontajnerovú virtualizáciu aplikácií, z ktorých najvýraznejším a najznámejším predstaviteľom je Docker. V porovnaní s predchádzajúcimi systémami flexibilnejšie mechanizmy izolácie spolu so vstavanou podporou virtuálnych sietí medzi kontajnermi a sledovaním stavu aplikácie vo vnútri kontajnera umožnili vytvoriť komplexné prostredie z veľkého počtu fyzických serverov na spustenie kontajnerov — bez potreby manuálneho riadenia zdrojov.
Docker
Docker je najznámejší softvér na kontajnerizáciu aplikácií. Napísaný v programovacom jazyku Go, využíva štandardné funkcie jadra Linux — cgroups, namespaces, capabilities atď., ako aj súborové systémy Aufs a ďalšie podobné pre úsporu diskového priestoru.

Zdroj: wikimedia
Architektúra
Až do verzie 1.11 Docker fungoval ako jednotná služba, ktorá vykonávala všetky operácie s kontajnermi: sťahovanie obrazov pre kontajnery, spustenie kontajnerov, spracovanie API požiadaviek. Od verzie 1.11 bol Docker rozdelený na niekoľko častí, ktoré si navzájom spolupracujú: containerd, ktorý spracováva celý životný cyklus kontajnerov (alokácia diskového priestoru, sťahovanie obrazov, práca so sieťou, spustenie, inštalácia a sledovanie stavu kontajnerov) a runC, prostredie vykonávania kontajnerov založené na využívaní cgroups a iných funkcií jadra Linux. Samotná služba Docker zostala, ale teraz slúži iba na spracovanie API požiadaviek, ktoré sú prenášané do containerd.

Inštalácia a nastavenie
Mojím obľúbeným spôsobom inštalácie Docker je docker-machine, ktorá okrem samotnej inštalácie a nastavenia Docker na vzdialených serveroch (vrátane rôznych cloudových služieb) umožňuje pracovať so súborovými systémami vzdialených serverov a môže vykonávať rôzne príkazy.
Avšak od roku 2018 projekt takmer nevyvíja, preto inštaláciu vykonáme štandardným spôsobom pre väčšinu distribúcií Linux — pridaním repozitára a inštaláciou potrebných balíkov.
Tento spôsob sa používa aj pri automatizovanej inštalácii, napríklad pomocou Ansible alebo iných podobných systémov, ale v tomto článku sa mu nebudem podrobne venovať.
Inštalácia sa bude vykonávať na Centos 7, ako server použijem virtuálny stroj, na inštaláciu stačí vykonať nasledujúce prí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 inštalácii treba spustiť službu a pridať ju do automatického spúšťania:
# systemctl enable docker
# systemctl start docker
# firewall-cmd --zone=public --add-port=2377/tcp --permanentOkrem toho môžete vytvoriť skupinu docker, ktorej používatelia môžu pracovať s docker bez sudo, nastaviť logovanie, povoliť prístup k API z vonku, nezabudnúť presnejšie nastaviť firewall (zakázané je všetko, čo nie je povolené, v príkladoch vyššie a nižšie to opúšťam pre jednoduchosť a prehľadnosť), ale tu sa nebudem podrobnejšie zaoberať.
Ďalšie možnosti
Okrem uvedenej docker machine existuje aj docker registry, nástroj na ukladanie obrazov pre kontejnery, ako aj docker compose - nástroj na automatizáciu nasadzovania aplikácií v kontejnere, využívajúci súbory YAML na zostavenie a konfiguráciu kontajnerov a ďalších súvisiacich vecí (napríklad siete, trvalé súborové systémy na uchovávanie údajov).
Taktiež s jeho pomocou môžete vytvoriť potrubia pre CICD. Ďalšou zaujímavou možnosťou je prevádzka v režime klasteru, nazývanom swarm mode (do verzie 1.12 bol známy ako docker swarm), ktorý umožňuje vytvoriť z viacerých serverov jednotnú infraštruktúru na spúšťanie kontajnerov. Existuje podpora virtuálnej siete nad všetkými servermi, prítomnosť zabudovaného vyvažovača záťaže, ako aj podpora tajomstiev pre kontajnery.
Súbory YAML z docker compose s malými zmenami môžu byť použité pre takéto klastre, úplne automatizujúc údržbu malých a stredných klastrov pre rôzne účely. Pre veľké klastre je lepšie používať Kubernetes, pretože náklady na údržbu swarm mode môžu prekročiť náklady s Kubernetes. Okrem runC ako prostredie vykonávania kontajnerov môžete nainštalovať napríklad
Práca s Docker
Po inštalácii a nastavení skúsime zriadiť klaster, v ktorom rozbehneme GitLab a Docker Registry pre vývojársky tím. Ako servery použijem tri virtuálne stroje, na ktorých navyše nasadím distribuovaný súborový systém GlusterFS, ktorý použijem ako úložisko docker volumes, napríklad na spustenie vysoko dostupnej verzie docker registry. Kľúčové komponenty na spustenie: Docker Registry, Postgresql, Redis, GitLab s podporou GitLab Runner nad Swarm. Postgresql spustíme s klastrovaním. , preto na uchovávanie dát Postgresql netreba používať GlusterFS. Ostatné kritické dáta budú uložené na GlusterFS.
Na zriadenie GlusterFS na všetkých serveroch (tie sú pomenované node1, node2, node3) je potrebné nainštalovať balíky, povoliť pracovný firewall a vytvoriť potrebné adresáre:
# 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 inštalácii je potrebné pokračovať v nastavení GlusterFS z jedného uzla, naprí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 dockerPotom je potrebné pripojiť získaný volume (príkaz treba vykonať na všetkých serveroch):
# mount /srv/dockerNastavenie swarm mode sa vykonáva na jednom zo serverov, ktorý bude Leader, ostatné sa musia pripojiť ku klastru, preto výsledok vykonania príkazu na prvom serveri je potrebné skopírovať a vykonať na ostatných.
Počiatočné nastavenie klastru, príkaz spúšťam 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 managerKopírujeme výsledok druhého príkazu, vykonávame 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 mieste je predbežné nastavenie serverov ukončené, prechádzame k nastaveniu služieb, príkazy na vykonanie budú spúšťané z node1, ak nie je uvedené inak.
Ako prvé vytvoríme siete pre kontajnery:
# 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 gitlabPotom označíme servery, to je potrebné na priradenie niektorých služieb k serverom:
# docker node update --label-add nodename=node1 node1
# docker node update --label-add nodename=node2 node2
# docker node update --label-add nodename=node3 node3Následne vytvárame adresáre na uchovávanie dát etcd, KV úložiska, ktoré je potrebné pre Traefik a Stolon. Podobne ako Postgresql to budú priradené k serverom kontajnery, preto tento príkaz vykonávame na všetkých serveroch:
# mkdir -p /srv/etcdPotom vytvárame súbor na nastavenie etcd a aplikujeme ho:
00etcd.yml
version: '3.7'
services:
etcd1:
image: quay.io/coreos/etcd:latest
hostname: etcd1
command:
- 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
networks:
- etcd
volumes:
- etcd1vol:/data.etcd
deploy:
replicas: 1
placement:
constraints: [node.labels.nodename == node1]
etcd2:
image: quay.io/coreos/etcd:latest
hostname: etcd2
command:
- 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
networks:
- etcd
volumes:
- etcd2vol:/data.etcd
deploy:
replicas: 1
placement:
constraints: [node.labels.nodename == node2]
etcd3:
image: quay.io/coreos/etcd:latest
hostname: etcd3
command:
- 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
networks:
- etcd
volumes:
- etcd3vol:/data.etcd
deploy:
replicas: 1
placement:
constraints: [node.labels.nodename == node3]
volumes:
etcd1vol:
driver: local
driver_opts:
type: none
o: bind
device: "/srv/etcd"
etcd2vol:
driver: local
driver_opts:
type: none
o: bind
device: "/srv/etcd"
etcd3vol:
driver: local
driver_opts:
type: none
o: bind
device: "/srv/etcd"
networks:
etcd:
external: true# docker stack deploy --compose-file 00etcd.yml etcdPo chvíli skontrolujeme, že sa spustil cluster etcd:
# 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 healthyVytvárame adresáre pre Postgresql, príkaz vykonáme na všetkých serveroch:
# mkdir -p /srv/pgsqlNásledne vytvoríme súbor na konfiguráciu Postgresql:
01pgsql.yml
verzia: '3.7'
služby:
pgsentinel:
obraz: sorintlab/stolon:master-pg10
prí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
siete:
- etcd
- pgsql
nasadenie:
repliky: 3
update_config:
paralelizmus: 1
oneskorenie: 30s
poradie: stop-first
failure_action: pause
pgkeeper1:
obraz: sorintlab/stolon:master-pg10
hostname: pgkeeper1
prí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
siete:
- etcd
- pgsql
prostredie:
- PGDATA=/var/lib/postgresql/data
objemy:
- pgkeeper1:/var/lib/postgresql/data
tajomstvá:
- pgsql
- pgsql_repl
nasadenie:
repliky: 1
umiestnenie:
obmedzenia: [node.labels.nodename == node1]
pgkeeper2:
obraz: sorintlab/stolon:master-pg10
hostname: pgkeeper2
prí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
siete:
- etcd
- pgsql
prostredie:
- PGDATA=/var/lib/postgresql/data
objemy:
- pgkeeper2:/var/lib/postgresql/data
tajomstvá:
- pgsql
- pgsql_repl
nasadenie:
repliky: 1
umiestnenie:
obmedzenia: [node.labels.nodename == node2]
pgkeeper3:
obraz: sorintlab/stolon:master-pg10
hostname: pgkeeper3
prí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
siete:
- etcd
- pgsql
prostredie:
- PGDATA=/var/lib/postgresql/data
objemy:
- pgkeeper3:/var/lib/postgresql/data
tajomstvá:
- pgsql
- pgsql_repl
nasadenie:
repliky: 1
umiestnenie:
obmedzenia: [node.labels.nodename == node3]
postgresql:
obraz: sorintlab/stolon:master-pg10
prí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
siete:
- etcd
- pgsql
nasadenie:
repliky: 3
update_config:
paralelizmus: 1
oneskorenie: 30s
poradie: stop-first
failure_action: rollback
objemy:
pgkeeper1:
ovládač: local
ovládacie_ponuky:
typ: none
o: bind
zariadenie: "/srv/pgsql"
pgkeeper2:
ovládač: local
ovládacie_ponuky:
typ: none
o: bind
zariadenie: "/srv/pgsql"
pgkeeper3:
ovládač: local
ovládacie_ponuky:
typ: none
o: bind
zariadenie: "/srv/pgsql"
tajomstvá:
pgsql:
súbor: "/srv/docker/postgres"
pgsql_repl:
súbor: "/srv/docker/replica"
siete:
etcd:
externé: true
pgsql:
externé: trueGenerujeme tajomstvá, používame súbor:
# </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 chvíli (pozrite si výstup príkazu docker service ls, čo potvrdzuje, že všetky služby sú spustené) inicializujeme klaster 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 pripravenosť klastera 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
Konfigurujeme traefik na sprístupnenie kontajnerov zvonka:
03traefik.yml
version: '3.7'
services:
traefik:
image: traefik:latest
command: >
--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
networks:
- traefik
ports:
- 80:80
volumes:
- /var/run/docker.sock:/var/run/docker.sock
deploy:
replicas: 3
placement:
constraints:
- node.role == manager
preferences:
- spread: node.id
labels:
- traefik.enable=true
- traefik.http.routers.traefik.rule=Host(`traefik.example.com`)
- traefik.http.services.traefik.loadbalancer.server.port=8080
- traefik.docker.network=traefik
networks:
traefik:
external: true# docker stack deploy --compose-file 03traefik.yml traefikSpúšťame Redis Cluster, na to vytvoríme na všetkých uzloch adresár na ukladanie:
# mkdir -p /srv/redis05redis.yml
version: '3.7'
services:
redis-master:
image: 'bitnami/redis:latest'
networks:
- redis
ports:
- '6379:6379'
environment:
- REDIS_REPLICATION_MODE=master
- REDIS_PASSWORD=xxxxxxxxxxx
deploy:
mode: global
restart_policy:
condition: any
volumes:
- 'redis:/opt/bitnami/redis/etc/'
redis-replica:
image: 'bitnami/redis:latest'
networks:
- redis
ports:
- '6379'
depends_on:
- redis-master
environment:
- REDIS_REPLICATION_MODE=slave
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_PASSWORD=xxxxxxxxxxx
- REDIS_PASSWORD=xxxxxxxxxxx
deploy:
mode: replicated
replicas: 3
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: any
redis-sentinel:
image: 'bitnami/redis:latest'
networks:
- redis
ports:
- '16379'
depends_on:
- redis-master
- redis-replica
entrypoint: |
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'
deploy:
mode: global
restart_policy:
condition: any
volumes:
redis:
driver: local
driver_opts:
type: 'none'
o: 'bind'
device: "/srv/redis"
networks:
redis:
external: true# docker stack deploy --compose-file 05redis.yml redisPridávame Docker Registry:
06registry.yml
verzia: '3.7'
služby:
registry:
image: registry:2.6
siete:
- traefik
objemy:
- registry_data: /var/lib/registry
nasadenie:
repliky: 1
umiestnenie:
obmedzenia: [node.role == manager]
politika_reštartu:
podmienka: 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
objemy:
registry_data:
ovládač: local
ovládač_opts:
typ: none
o: bind
zariadenie: "/srv/docker/registry"
siete:
traefik:
externé: true# mkdir /srv/docker/registry
# docker stack deploy --compose-file 06registry.yml registryA nakoniec — GitLab:
08gitlab-runner.yml
verzia: '3.7'
služby:
gitlab:
image: gitlab/gitlab-ce:latest
siete:
- pgsql
- redis
- traefik
- gitlab
porty:
- 22222:22
prostredie:
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
objemy:
- gitlab_conf:/etc/gitlab
- gitlab_logs:/var/log/gitlab
- gitlab_data:/var/opt/gitlab
nasadenie:
mód: replicated
repliky: 1
umiestnenie:
obmedzenia:
- 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:
image: gitlab/gitlab-runner:latest
siete:
- gitlab
objemy:
- gitlab_runner_conf:/etc/gitlab
- /var/run/docker.sock:/var/run/docker.sock
nasadenie:
mód: replicated
repliky: 1
umiestnenie:
obmedzenia:
- node.role == manager
objemy:
gitlab_conf:
ovládač: local
ovládač_opts:
typ: none
o: bind
zariadenie: "/srv/docker/gitlab/conf"
gitlab_logs:
ovládač: local
ovládač_opts:
typ: none
o: bind
zariadenie: "/srv/docker/gitlab/logs"
gitlab_data:
ovládač: local
ovládač_opts:
typ: none
o: bind
zariadenie: "/srv/docker/gitlab/data"
gitlab_runner_conf:
ovládač: local
ovládač_opts:
typ: none
o: bind
zariadenie: "/srv/docker/gitlab/runner"
siete:
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 klastra a služieb:
# 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/tcpČo ešte možno vylepšiť? Určite nastaviť v Traefik prácu kontajnerov cez https, pridať šifrovanie tls pre Postgresql a Redis. Ale celkovo už to možno odovzdať vývojárom ako PoC. Teraz sa pozrime na alternatívy Dockeru.
Podman
Ďalší dosť známy engine na spúšťanie kontajnerov, skupinových po pods (pods, skupiny kontajnerov nasadených spoločne). Na rozdiel od Dockeru nevyžaduje žiadny servis na spúšťanie kontajnerov, všetka práca sa vykonáva cez knižnicu libpod. Tiež napísaný v Go, vyžaduje OCI-kompatibilný runtime na spúšťanie kontajnerov, napríklad runC.

Práca s Podmanom vo všeobecnosti pripomína prácu s Dockerom, až po to, že môžete spraviť takto (tvrdené mnohými, ktorí to vyskúšali, vrátane autora tohto článku):
$ alias docker=podmana môžete pokračovať v práci. Všeobecne situácia s Podmanom je veľmi zaujímavá, pretože ak rané verzie Kubernetes pracovali s Dockerom, od približne roku 2015, po standardizácii sveta kontajnerov (OCI — Open Container Initiative) a rozdelení Dockeru na containerd a runC, sa vyvíja alternatíva Dockeru na spúšťanie v Kubernetes: CRI-O. Podman v tomto ohľade je alternatívou Dockeru postavenou na princípoch Kubernetes, vrátane skupinovania kontajnerov, ale hlavný cieľ existencie projektu — spúšťanie kontajnerov v štýle Docker bez dodatočných služieb. Z zrozumiteľných dôvodov nie je prítomný swarm mode, pretože vývojári jasne hovoria, že ak potrebujete klaster — berte Kubernetes.
Inštalácia
Na inštaláciu v Centos 7 stačí aktivovať repozitár Extras, po čom nainštalujeme všetko príkazom:
# yum -y install podmanĎalšie možnosti
Podman môže generovať jednotky pre systemd, čím rieši úlohu spúšťania kontajnerov po reštartovaní servera. Navyše bola deklarovaná správna práca systemd ako pid 1 v kontajneri. Na zostavenie kontajnerov existuje samostatný nástroj buildah, sú tiež k dispozícii externé nástroje — analógy docker-compose, ktorý generuje aj konfiguračné súbory kompatibilné s Kubernetes, takže prechod z Podman na Kubernetes je zjednodušený, ak je to možné.
Práca s Podmanom
Keďže nie je prítomný swarm mode (predpokladá sa prechod na Kubernetes, ak potrebujete klaster) — budeme zbierať jednotlivé kontajnery.
Inštalujeme podman-compose:
# yum -y install python3-pip
# pip3 install podman-composeVýsledný konfiguračný súbor pre podman sa trochu líši, napríklad bolo potrebné presunúť samostatnú sekciu volumes priamo do sekcie so službami.
gitlab-podman.yml
verzia: '3.7'
služby:
gitlab:
obraz: gitlab/gitlab-ce:latest
hostname: gitlab.example.com
restart: unless-stopped
prostredie:
GITLAB_OMNIBUS_CONFIG: |
gitlab_rails['gitlab_shell_ssh_port'] = 22222
porty:
- "80:80"
- "22222:22"
objemy:
- /srv/podman/gitlab/conf:/etc/gitlab
- /srv/podman/gitlab/data:/var/opt/gitlab
- /srv/podman/gitlab/logs:/var/log/gitlab
siete:
- gitlab
gitlab-runner:
obraz: gitlab/gitlab-runner:alpine
restart: unless-stopped
závisí_od:
- gitlab
objemy:
- /srv/podman/gitlab/runner:/etc/gitlab-runner
- /var/run/docker.sock:/var/run/docker.sock
siete:
- gitlab
siete:
gitlab:# podman-compose -f gitlab-runner.yml -d upVýsledok 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_1Pozrime sa, čo vygeneruje pre systemd a kubernetes, na to je potrebné zistiť meno alebo 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.targetŽiaľ, okrem spustenia kontajnerov generovaný jednotkový súbor pre systemd nič viac nerobí (napríklad vyčistenie starých kontajnerov pri reštarte takejto služby), takže tieto veci bude treba dopisovať samostatne.
V zásade Podman je dostatočný na to, aby ste vyskúšali, čo sú kontajnery, preniesli staré konfigurácie pre docker-compose, po čom môžete prejsť na Kubernetes, ak potrebujete na klaster, alebo získať jednoduchšiu alternatívu k Dockeru.
rkt
Projekt približne pred pol rokom, pretože ho kúpil RedHat, takže sa nebudem na ňom podrobne zastavovať. Celkovo zanechával celkom dobrý dojem, avšak v porovnaní s Dockerom a už vôbec s Podmanom vyzerá ako kombajn. Existoval tiež distribúcia CoreOS, postavená na základe rkt (aj keď pôvodne mali Docker), avšak jeho podpora tiež skončila po kúpe RedHat.
Plash
Ďalšie , autor ktorého chcel jednoducho zbierať a spúšťať kontajnery. Súdiac podľa dokumentácie a kódu - autor nedodržiaval štandardy, ale jednoducho sa rozhodol napísať svoju implementáciu, čo v podstate aj spravil.
Zhrnutie
Situácia pri existencii Kubernetes je veľmi zaujímavá: z jednej strany je možné postaviť klaster s Dockerom (v swarm móde), s ktorým je možné spúšťať produktové prostredia pre klientov, čo je obzvlášť aktuálne pre malé tímy (3-5 ľudí), alebo pri malej celkovej záťaži, či pri absencii ochoty rozumieť nuansám nastavenia Kubernetes, vrátane tých pre vysoké zaťaženia.
Podman nenabízí úplnou kompatibilitu, ale má jednu důležitou výhodu – kompatibilitu s Kubernetes, včetně dalších nástrojů (buildah a další). Proto k výběru nástroje pro práci přistupuji takto: pro malé týmy nebo při omezeném rozpočtu – Docker (s možným režimem swarm), pro vývoj pro sebe na osobním localhostu – 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 zároveň se postupně standardizují, ale Podman, i se všemi svými nedostatky (funguje pouze na Linuxu, nemá clustering, sestavování a další činnosti – prostřednictvím externích řešení), má jasnější budoucnost, proto zvu všechny zájemce, aby tyto závěry prodiskutovali v komentářích.
P.S. 3. srpna spouštíme „“, kde se můžete podrobněji seznámit s jeho funkcí. Projdeme si 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 je nejlepší Docker použít. Také se podělíme o best practice případy.
Cena předobjednávky před vydáním: 5000 Kč. S programem „Videokurzu o Dockeru“ se můžete seznámit .
Zdroj: habr.com
