TL;DR: een overzichtelijk gidsartikel ter vergelijking van omgevingen voor het uitvoeren van applicaties in containers. De mogelijkheden van Docker en andere soortgelijke systemen zullen worden besproken.

Een beetje historie, waar het allemaal vandaan komt
Geschiedenis
De eerste algemeen bekende manier van applicatie-isolatie is chroot. De gelijknamige systeemaanroep zorgt voor het wijzigen van de rootmap, waardoor het programma dat het oproept, alleen toegang heeft tot de bestanden binnen deze map. Maar als je het programma binnen superuser-rechten geeft, kan het potentieel 'ontsnappen' uit chroot en toegang krijgen tot het primaire besturingssysteem. Daarnaast zijn er geen beperkingen op andere middelen (werkgeheugen, processor) en toegang tot het netwerk, behalve de rootmap.
De volgende manier is het uitvoeren van een volledige besturingssysteem binnen een container, met behulp van de mechanismen van de besturingssysteemkernel. In verschillende besturingssystemen wordt deze methode anders genoemd, maar de essentie blijft hetzelfde — het draaien van meerdere onafhankelijke besturingssystemen, die elk werken met dezelfde kernel als het primaire besturingssysteem. Dit omvat FreeBSD Jails, Solaris Zones, OpenVZ en LXC voor Linux. Er wordt isolatie geboden, niet alleen op schijfruimte, maar ook op andere middelen; elk container kan bijvoorbeeld beperkingen hebben op de processor tijd, werkgeheugen en netwerksnelheid. In vergelijking met chroot is het moeilijker om uit de container te ontsnappen, omdat de superuser in de container alleen toegang heeft tot de inhoud van de container. Desondanks bestaat er door de noodzaak om het besturingssysteem binnen de container actueel te houden en het gebruik van oude kernelversies (vooral relevant voor Linux, in mindere mate FreeBSD) een niet-negligeerbare kans op het 'doorbreken' van het isolatiesysteem van de kernel en toegang tot het primaire besturingssysteem.
In plaats van een volledige besturingssysteem in een container (met init-systeem, pakketbeheer enz.) te starten, kunnen we direct applicaties uitvoeren, de belangrijkste vereiste is dat de applicaties de juiste mogelijkheden hebben (beschikbare bibliotheken en andere bestanden). Dit idee vormde de basis voor containervirtualisatie van applicaties, waarvan Docker de meest opvallende en bekende vertegenwoordiger is. In vergelijking met eerdere systemen hebben de flexibeler isolatiemechanismen, samen met de ingebouwde ondersteuning voor virtuele netwerken tussen containers en het volgen van de status van de applicatie binnen de container, uiteindelijk geleid tot de mogelijkheid om een samenhangende omgeving te creëren uit een groot aantal fysieke servers voor het draaien van containers - zonder handmatige resourcebeheer.
Docker
Docker is de bekendste software voor containerisatie van applicaties. Het is geschreven in Go en maakt gebruik van standaard mogelijkheden van de Linux-kernel - cgroups, namespaces, capabilities, enz., en ook bestandssystemen zoals Aufs en andere soortgelijke systemen voor schijfsparingen.

Bron: wikimedia
Architectuur
Tot versie 1.11 werkte Docker als een enkele service, die alle bewerkingen met containers uitvoerde: het downloaden van afbeeldingen voor containers, het starten van containers, het verwerken van API-verzoeken. Vanaf versie 1.11 is Docker opgesplitst in verschillende onderdelen die met elkaar communiceren: containerd voor het beheren van de volledige levenscyclus van containers (toewijzing van schijfruimte, downloaden van afbeeldingen, netwerken, starten, installeren en monitoren van de status van containers) en runC, een uitvoeringsomgeving voor containers, gebaseerd op het gebruik van cgroups en andere mogelijkheden van de Linux-kernel. De service docker zelf blijft bestaan, maar dient nu alleen voor het verwerken van API-verzoeken, die worden doorgegeven aan containerd.

Installatie en configuratie
Mijn favoriete methode om docker te installeren is via docker-machine, die, naast de directe installatie en configuratie van docker op externe servers (inclusief verschillende cloud-omgevingen), ook de mogelijkheid biedt om met de bestandssystemen van externe servers te werken, en verschillende opdrachten kan uitvoeren.
Echter, sinds 2018 is het project nauwelijks ontwikkeld, daarom zullen we de standaardmethode voor de meeste Linux-distributies gebruiken — het toevoegen van een repository en het installeren van de benodigde pakketten.
Deze methode wordt ook toegepast bij geautomatiseerde installatie, bijvoorbeeld met behulp van Ansible of andere soortgelijke systemen, maar in dit artikel zal ik dat niet behandelen.
De installatie zal plaatsvinden op CentOS 7, en als server zal ik een virtuele machine gebruiken; om de installatie uit te voeren, volstaat het om de onderstaande commando's uit te voeren:
# 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.ioNa de installatie moet je de service starten en deze instellen voor automatisch opstarten:
# systemctl enable docker
# systemctl start docker
# firewall-cmd --zone=public --add-port=2377/tcp --permanentDaarnaast kun je een groep 'docker' aanmaken, waarvan de gebruikers zonder sudo met docker kunnen werken, logging instellen, toegang tot de API van buitenaf inschakelen, en vergeet niet de firewall beter af te stemmen (verboden is alles wat niet is toegestaan; in de voorbeelden hierboven en hieronder heb ik dit ter eenvoud en duidelijkheid weggelaten), maar hier ga ik niet verder op in.
Andere mogelijkheden
Naast de eerder genoemde docker machine zijn er ook docker registry, een hulpmiddel voor het opslaan van afbeeldingen voor containers, en docker compose — een middel voor het automatiseren van de uitrol van applicaties in containers, waarbij YAML-bestanden worden gebruikt voor het opbouwen en configureren van containers en andere gerelateerde zaken (zoals netwerken en permanente bestandssystemen voor dataopslag).
Met dit hulpmiddel kun je ook pijplijnen voor CICD opzetten. Een andere interessante mogelijkheid is het werken in een cluster-modus, ook wel swarm-modus genoemd (voor versie 1.12 stond dit bekend als docker swarm), die het mogelijk maakt om uit meerdere servers één infrastructuur voor het draaien van containers te creëren. Er is ondersteuning voor een virtueel netwerk over alle servers, een ingebouwde load balancer, en ondersteuning voor geheimen voor containers.
YAML-bestanden van docker compose kunnen met kleine aanpassingen worden gebruikt voor dergelijke clusters, waarbij het onderhoud van kleine en middelgrote clusters volledig wordt geautomatiseerd voor verschillende doeleinden. Voor grote clusters heeft Kubernetes de voorkeur, omdat de onderhoudskosten van swarm-modus hoger kunnen zijn dan die van Kubernetes. Naast runC kun je bijvoorbeeld
Werken met Docker
Na afloop van de installatie en configuratie gaan we een cluster opzetten waarin we GitLab en Docker Registry voor het ontwikkelteam zullen implementeren. Voor de servers gebruik ik drie virtuele machines, waarop ik aanvullend een gedistribueerd bestandssysteem GlusterFS zal opzetten, dat ik zal gebruiken als opslag voor docker volumes, bijvoorbeeld voor het draaien van een fouttolerante versie van de docker registry. De belangrijkste componenten voor de opzet zijn: Docker Registry, Postgresql, Redis, GitLab met ondersteuning voor GitLab Runner bovenop Swarm. We zullen Postgresql met clustering draaien. , daarom hoeft GlusterFS niet voor de opslag van Postgresql-gegevens te worden gebruikt. Andere kritieke gegevens zullen op GlusterFS worden opgeslagen.
Voor het implementeren van GlusterFS op alle servers (deze worden node1, node2, node3 genoemd) moeten we pakketten installeren, de firewall toestaan, en de benodigde mappen aanmaken:
# 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/fstabNa de installatie moet de configuratie van GlusterFS worden voortgezet vanaf één knooppunt, bijvoorbeeld 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 dockerVervolgens moet de verkregen volume worden gemonteerd (de opdracht moet op alle servers worden uitgevoerd):
# mount /srv/dockerDe configuratie van de swarm-modus wordt uitgevoerd op een van de servers, die de leider zal zijn; de anderen moeten zich bij het cluster aansluiten, daarom moet het resultaat van de opdracht op de eerste server worden gekopieerd en op de overige uitgevoerd.
De initiële configuratie van het cluster, de opdracht wordt uitgevoerd op 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 managerWe kopiëren het resultaat van de tweede opdracht, uitvoeren op node2 en node3:
# docker swarm join --token SWMTKN-x-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxx xx.xx.xx.xx:2377
This node joined a swarm as a manager.Nu is de voorlopige configuratie van de servers voltooid, we gaan verder met de configuratie van de services, de opdrachten die uitgevoerd moeten worden worden gestart vanaf node1, tenzij anders aangegeven.
Laten we als eerste netwerken voor de containers aanmaken:
# 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 gitlabDaarna markeren we de servers; dit is nodig om bepaalde services aan servers te koppelen:
# docker node update --label-add nodename=node1 node1
# docker node update --label-add nodename=node2 node2
# docker node update --label-add nodename=node3 node3Vervolgens creëren we mappen voor de opslag van data van etcd, een KV-opslagplaats die nodig is voor Traefik en Stolon. Net als bij Postgresql zullen dit gekoppelde containers aan de servers zijn, daarom voeren we deze opdracht uit op alle servers:
# mkdir -p /srv/etcdDaarna maken we een bestand voor de configuratie van etcd en passen het toe:
00etcd.yml
versie: '3.7'
diensten:
etcd1:
afbeelding: quay.io/coreos/etcd:latest
hostname: etcd1
opdracht:
- 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
netwerken:
- etcd
volumes:
- etcd1vol:/data.etcd
implementatie:
replicas: 1
plaatsing:
beperkingen: [node.labels.nodename == node1]
etcd2:
afbeelding: quay.io/coreos/etcd:latest
hostname: etcd2
opdracht:
- 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
netwerken:
- etcd
volumes:
- etcd2vol:/data.etcd
implementatie:
replicas: 1
plaatsing:
beperkingen: [node.labels.nodename == node2]
etcd3:
afbeelding: quay.io/coreos/etcd:latest
hostname: etcd3
opdracht:
- 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
netwerken:
- etcd
volumes:
- etcd3vol:/data.etcd
implementatie:
replicas: 1
plaatsing:
beperkingen: [node.labels.nodename == node3]
volumes:
etcd1vol:
driver: lokaal
driver_opts:
type: none
o: bind
device: "/srv/etcd"
etcd2vol:
driver: lokaal
driver_opts:
type: none
o: bind
device: "/srv/etcd"
etcd3vol:
driver: lokaal
driver_opts:
type: none
o: bind
device: "/srv/etcd"
netwerken:
etcd:
extern: true# docker stack deploy --compose-file 00etcd.yml etcdNa enige tijd controleren we of het etcd-cluster is opgestart:
# 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 healthyWe maken mappen voor PostgreSQL, de opdracht wordt op alle servers uitgevoerd:
# mkdir -p /srv/pgsqlLaten we nu een bestand aanmaken voor de PostgreSQL-configuratie:
01pgsql.yml
versie: '3.7'
diensten:
pgsentinel:
afbeelding: sorintlab/stolon:master-pg10
opdracht:
- 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
netwerken:
- etcd
- pgsql
implementatie:
replicas: 3
update_config:
parallelisme: 1
vertraging: 30s
volgorde: stop-eerst
failure_action: pauze
pgkeeper1:
afbeelding: sorintlab/stolon:master-pg10
hostnaam: pgkeeper1
opdracht:
- 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
netwerken:
- etcd
- pgsql
omgeving:
- PGDATA=/var/lib/postgresql/data
volumes:
- pgkeeper1:/var/lib/postgresql/data
secrets:
- pgsql
- pgsql_repl
implementatie:
replicas: 1
plaatsing:
beperkingen: [node.labels.nodename == node1]
pgkeeper2:
afbeelding: sorintlab/stolon:master-pg10
hostnaam: pgkeeper2
opdracht:
- 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
netwerken:
- etcd
- pgsql
omgeving:
- PGDATA=/var/lib/postgresql/data
volumes:
- pgkeeper2:/var/lib/postgresql/data
secrets:
- pgsql
- pgsql_repl
implementatie:
replicas: 1
plaatsing:
beperkingen: [node.labels.nodename == node2]
pgkeeper3:
afbeelding: sorintlab/stolon:master-pg10
hostnaam: pgkeeper3
opdracht:
- 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
netwerken:
- etcd
- pgsql
omgeving:
- PGDATA=/var/lib/postgresql/data
volumes:
- pgkeeper3:/var/lib/postgresql/data
secrets:
- pgsql
- pgsql_repl
implementatie:
replicas: 1
plaatsing:
beperkingen: [node.labels.nodename == node3]
postgresql:
afbeelding: sorintlab/stolon:master-pg10
opdracht: 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
netwerken:
- etcd
- pgsql
implementatie:
replicas: 3
update_config:
parallelisme: 1
vertraging: 30s
volgorde: stop-eerst
failure_action: rollback
volumes:
pgkeeper1:
driver: local
driver_opts:
type: none
o: bind
apparaat: "/srv/pgsql"
pgkeeper2:
driver: local
driver_opts:
type: none
o: bind
apparaat: "/srv/pgsql"
pgkeeper3:
driver: local
driver_opts:
type: none
o: bind
apparaat: "/srv/pgsql"
secrets:
pgsql:
bestand: "/srv/docker/postgres"
pgsql_repl:
bestand: "/srv/docker/replica"
netwerken:
etcd:
extern: true
pgsql:
extern: trueWe zijn aan het genereren van geheimen, pas het bestand toe:
# </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 pgsqlNa enige tijd (we bekijken de uitvoer van de commande docker service ls, die aangeeft dat alle services zijn opgestart) initialiseren we de Postgresql-cluster:
# 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 initWe controleren de gereedheid van de Postgresql-cluster:
# 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
We configureren traefik voor externe toegang tot de containers:
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 traefikWe starten de Redis-cluster, hiervoor maken we op alle knooppunten een map voor opslag aan:
# 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 redisWe voegen een Docker Registry toe:
06registry.yml
versie: '3.7'
services:
registry:
image: registry:2.6
networks:
- traefik
volumes:
- registry_data:/var/lib/registry
deploy:
replicas: 1
placement:
constraints: [node.role == manager]
restart_policy:
condition: on-failure
labels:
- traefik.enable=true
- traefik.http.routers.registry.rule=Host(`registry.example.com`)
- traefik.http.services.registry.loadbalancer.server.port=5000
- traefik.docker.network=traefik
volumes:
registry_data:
driver: local
driver_opts:
type: none
o: bind
device: "/srv/docker/registry"
networks:
traefik:
external: true# mkdir /srv/docker/registry
# docker stack deploy --compose-file 06registry.yml registryEn tot slot — GitLab:
08gitlab-runner.yml
versie: '3.7'
services:
gitlab:
image: gitlab/gitlab-ce:latest
networks:
- pgsql
- redis
- traefik
- gitlab
ports:
- 22222:22
environment:
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
volumes:
- gitlab_conf:/etc/gitlab
- gitlab_logs:/var/log/gitlab
- gitlab_data:/var/opt/gitlab
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.role == manager
labels:
- 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
networks:
- gitlab
volumes:
- gitlab_runner_conf:/etc/gitlab
- /var/run/docker.sock:/var/run/docker.sock
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.role == manager
volumes:
gitlab_conf:
driver: local
driver_opts:
type: none
o: bind
device: "/srv/docker/gitlab/conf"
gitlab_logs:
driver: local
driver_opts:
type: none
o: bind
device: "/srv/docker/gitlab/logs"
gitlab_data:
driver: local
driver_opts:
type: none
o: bind
device: "/srv/docker/gitlab/data"
gitlab_runner_conf:
driver: local
driver_opts:
type: none
o: bind
device: "/srv/docker/gitlab/runner"
networks:
pgsql:
external: true
redis:
external: true
traefik:
external: true
gitlab:
external: 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 gitlabEindtoestand van de cluster en services:
# 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/tcpWat kan nog verbeterd worden? Zorg ervoor dat Traefik de containers via https configureert, voeg tls-encryptie toe voor Postgresql en Redis. Maar in het algemeen kan het nu al aan de ontwikkelaars worden gegeven als PoC. Laten we nu de alternatieven voor Docker bekijken.
Podman
Een andere redelijk bekende engine voor het starten van containers, gegroepeerd in pods (pods, groepen containers die samen worden uitgerold). In tegenstelling tot Docker vereist het geen enkele service voor het starten van containers; al het werk gebeurt via de libpod-bibliotheek. Het is ook geschreven in Go en heeft een OCI-compatibele runtime nodig voor het starten van containers, zoals runC.

Werken met Podman lijkt in grote lijnen op werken met Docker, tot het punt dat je het zo kunt doen (zoals velen die het hebben geprobeerd, inclusief de auteur van dit artikel, hebben aangegeven):
$ alias docker=podmanen je kunt doorgaan met werken. Over het algemeen is de situatie met Podman behoorlijk interessant, want als eerdere versies van Kubernetes met Docker werkten, zijn vanaf ongeveer 2015, na de standaardisatie van de containerwereld (OCI - Open Container Initiative) en het splitsen van Docker in containerd en runC, alternatieven voor Docker voor gebruik in Kubernetes aan het ontwikkelen: CRI-O. Podman is in dat opzicht een alternatief voor Docker, gebaseerd op de principes van Kubernetes, inclusief het groeperen van containers. Maar het belangrijkste doel van het project is het starten van containers in de stijl van Docker zonder extra services. Om duidelijke redenen is er geen swarm-modus, omdat de ontwikkelaars expliciet zeggen dat als je een cluster nodig hebt, je Kubernetes moet nemen.
Installatie
Voor installatie op Centos 7 is het voldoende om de Extras-repository te activeren, waarna je alles kunt installeren met het commando:
# yum -y install podmanAndere mogelijkheden
Podman kan eenheden genereren voor systemd, waardoor het probleem van het starten van containers na een serverherstart wordt opgelost. Daarnaast is het correct functioneren van systemd als pid 1 in de container bevestigd. Voor het bouwen van containers is er een aparte tool genaamd buildah, ook zijn er externe tools - analogieën voor docker-compose - die ook configuratiebestanden genereren die compatibel zijn met Kubernetes, zodat de overgang van Podman naar Kubernetes zo vereenvoudigd mogelijk is.
Werken met Podman
Aangezien er geen swarm-modus is (de overgang naar Kubernetes wordt verondersteld als een cluster nodig is) - we verzamelen aparte containers.
We installeren podman-compose:
# yum -y install python3-pip
# pip3 install podman-composeHet resulterende configuratiebestand voor podman verschilt een beetje; bijvoorbeeld moesten we een aparte sectie volumes rechtstreeks naar de sectie met services verplaatsen.
gitlab-podman.yml
versie: '3.7'
diensten:
gitlab:
afbeelding: gitlab/gitlab-ce:latest
hostname: gitlab.example.com
herstart: tenzij-stop
omgeving:
GITLAB_OMNIBUS_CONFIG: |
gitlab_rails['gitlab_shell_ssh_port'] = 22222
poorten:
- "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
netwerken:
- gitlab
gitlab-runner:
afbeelding: gitlab/gitlab-runner:alpine
herstart: tenzij-stop
afhankelijk_van:
- gitlab
volumes:
- /srv/podman/gitlab/runner:/etc/gitlab-runner
- /var/run/docker.sock:/var/run/docker.sock
netwerken:
- gitlab
netwerken:
gitlab:# podman-compose -f gitlab-runner.yml -d upResultaat:
# 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_1Laten we kijken wat het genereert voor systemd en kubernetes, hiervoor moeten we de naam of id van de pod achterhalen:
# 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.targetHelaas doet de gegenereerde eenheid voor systemd verder niets dan het starten van containers (bijvoorbeeld het opruimen van oude containers bij het opnieuw starten van zo'n service), dus dergelijke dingen zullen handmatig moeten worden toegevoegd.
In principe is Podman voldoende om uit te proberen wat containers zijn, oude configuraties voor docker-compose over te zetten, waarna je naar Kubernetes kunt overstappen, als dat nodig is voor een cluster, of een eenvoudigere werkbare alternatief voor Docker kunt verkrijgen.
rkt
Project ongeveer zes maanden geleden omdat het door RedHat is gekocht, dus ik zal er niet dieper op ingaan. Over het algemeen maakte het een vrij goede indruk, maar vergeleken met Docker en vooral met Podman lijkt het een combinatie van middelen. Er was ook een distributie CoreOS, gebouwd op basis van rkt (hoewel ze oorspronkelijk Docker hadden), maar de ondersteuning daarvan eindigde ook na de aankoop door RedHat.
Plash
Meer , waarvan de auteur gewoon containers wilde bouwen en draaien. Afgaand op de documentatie en de code - de auteur volgde de standaarden niet, maar besloot gewoon zijn eigen implementatie te schrijven, wat hij in principe ook deed.
Conclusies
De situatie met Kubernetes is vrij interessant: aan de ene kant kun je met Docker een cluster opbouwen (in swarm-modus), waarmee je zelfs productieomgevingen voor klanten kunt draaien, wat vooral relevant is voor kleine teams (3-5 mensen), of bij een geringe totale belasting, of een gebrek aan verlangen om in de details van de configuratie van Kubernetes te duiken, inclusief voor hoge belastingen.
Podman biedt niet volledige compatibiliteit, maar het heeft één belangrijk voordeel: de compatibiliteit met Kubernetes, inclusief extra tools (zoals buildah en anderen). Daarom benader ik de keuze van de tool als volgt: voor kleine teams of met een beperkt budget — Docker (met mogelijk swarm-modus), voor ontwikkeling op een persoonlijke localhost — Podman met collega's, en voor iedereen anderen — Kubernetes.
Ik ben niet zeker of de situatie met Docker in de toekomst zal veranderen, ze zijn tenslotte pioniers en ze worden stap voor stap steeds meer gestandaardiseerd. Maar Podman heeft, ondanks al zijn tekortkomingen (werkt alleen op Linux, geen clustering, bouwen en andere acties vereist externe oplossingen), een duidelijkere toekomst. Daarom nodig ik iedereen die geïnteresseerd is uit om deze conclusies in de reacties te bespreken.
P.S. 3 augustus lanceren we "", waar je meer te weten kunt komen over de werking ervan. We zullen al zijn tools behandelen: van de belangrijkste abstracties tot netwerkinstellingen, de nuances van werken met verschillende besturingssystemen en programmeertalen. Je leert de technologie kennen en begrijpt waar en hoe je Docker het beste kunt gebruiken. We delen ook best practice cases.
De voorverkoopprijs tot de release: 5000 r. Je kunt het programma "Videocursus over Docker" vinden .
Bron: habr.com
