TL;DR: een overzichtsartikel - een gids voor het vergelijken van omgevingen voor het uitvoeren van applicaties in containers. Er wordt gekeken naar de mogelijkheden van Docker en andere vergelijkbare systemen.
Een beetje geschiedenis van waar het allemaal vandaan kwam
Verhaal
De eerste bekende manier om een applicatie te isoleren is chroot. De systeemaanroep met dezelfde naam zorgt voor een wijziging in de hoofdmap - waardoor toegang wordt verkregen tot het programma dat het heeft aangeroepen, alleen toegang tot bestanden in deze map. Maar als het programma binnenin superuser-rechten krijgt, kan het potentieel "ontsnappen" uit de chroot en toegang krijgen tot het hoofdbesturingssysteem. Naast het wijzigen van de hoofdmap zijn ook andere bronnen (RAM, processor) en toegang tot het netwerk niet beperkt.
De volgende manier is om een volwaardig besturingssysteem in de container te lanceren, met behulp van de mechanismen van de kernel van het besturingssysteem. Deze methode wordt in verschillende besturingssystemen anders genoemd, maar de essentie is hetzelfde: het uitvoeren van verschillende onafhankelijke besturingssystemen, die allemaal op dezelfde kernel draaien waarop het hoofdbesturingssysteem draait. Dit omvat FreeBSD Jails, Solaris Zones, OpenVZ en LXC voor Linux. Isolatie wordt niet alleen geboden voor schijfruimte, maar ook voor andere bronnen, in het bijzonder kan elke container beperkingen hebben op processortijd, RAM, netwerkbandbreedte. In vergelijking met chroot is het moeilijker om de container te verlaten, aangezien de superuser in de container alleen toegang heeft tot de binnenkant van de container, vanwege de noodzaak om het besturingssysteem in de container up-to-date te houden en het gebruik van oude kernel versies (relevant voor Linux, in mindere mate FreeBSD), is er een niet-nul kans om door het kernel-isolatiesysteem te breken en toegang te krijgen tot het hoofdbesturingssysteem.
In plaats van een volwaardig besturingssysteem in een container te lanceren (met een initialisatiesysteem, een pakketbeheerder, enz.), kunnen applicaties onmiddellijk worden gestart, het belangrijkste is om applicaties deze mogelijkheid te bieden (de aanwezigheid van de nodige bibliotheken en andere bestanden). Dit idee diende als basis voor gecontaineriseerde applicatievirtualisatie, waarvan Docker de meest prominente en bekende vertegenwoordiger is. Vergeleken met eerdere systemen resulteerden flexibelere isolatiemechanismen, samen met ingebouwde ondersteuning voor virtuele netwerken tussen containers en applicatiestatus binnen een container, in de mogelijkheid om een enkele holistische omgeving te bouwen van een groot aantal fysieke servers om containers te draaien - zonder de behoefte aan handmatig resourcebeheer.
havenarbeider
Docker is de meest bekende applicatie-containerisatiesoftware. Geschreven in de Go-taal, gebruikt het de reguliere mogelijkheden van de Linux-kernel - cgroups, naamruimten, mogelijkheden, enz., evenals Aufs-bestandssystemen en andere soortgelijke om schijfruimte te besparen.
Bron: wikimedia
Architectuur
Voorafgaand aan versie 1.11 werkte Docker als een enkele service die alle bewerkingen met containers uitvoerde: afbeeldingen voor containers downloaden, containers lanceren, API-aanvragen verwerken. Sinds versie 1.11 is Docker opgesplitst in verschillende delen die met elkaar communiceren: containerd, om de volledige levenscyclus van containers af te handelen (toewijzing van schijfruimte, downloaden van afbeeldingen, netwerken, starten, installeren en bewaken van de staat van containers) en runC , container-runtimes, gebaseerd op het gebruik van cgroups en andere kenmerken van de Linux-kernel. De docker-service zelf blijft, maar dient nu alleen voor het verwerken van API-verzoeken die naar containerd worden uitgezonden.
Installatie en configuratie
Mijn favoriete manier om docker te installeren is docker-machine, waarmee je, naast het rechtstreeks installeren en configureren van docker op externe servers (inclusief verschillende clouds), kunt werken met de bestandssystemen van externe servers en ook verschillende opdrachten kunt uitvoeren.
Sinds 2018 is het project echter nauwelijks ontwikkeld, dus zullen we het op de gebruikelijke manier voor de meeste Linux-distributies installeren - door een repository toe te voegen en de benodigde pakketten te installeren.
Deze methode wordt ook gebruikt voor geautomatiseerde installatie, bijvoorbeeld met behulp van Ansible of andere vergelijkbare systemen, maar daar zal ik in dit artikel niet op ingaan.
De installatie zal worden uitgevoerd op Centos 7, ik zal een virtuele machine als server gebruiken om te installeren, voer gewoon de onderstaande opdrachten uit:
# 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.io
Na de installatie moet u de service starten, in autoload plaatsen:
# systemctl enable docker
# systemctl start docker
# firewall-cmd --zone=public --add-port=2377/tcp --permanent
Bovendien kunt u een docker-groep maken, waarvan de gebruikers zonder sudo met docker kunnen werken, logging instellen, toegang tot de API van buitenaf mogelijk maken, vergeet niet de firewall te verfijnen (alles wat niet is toegestaan, is verboden in de voorbeelden hierboven en hieronder - ik heb dit weggelaten voor de eenvoud en visualisatie), maar ik zal hier niet dieper op ingaan.
Andere functies
Naast de bovenstaande docker-machine is er ook een docker-register, een tool voor het opslaan van afbeeldingen voor containers, evenals docker compose - een tool voor het automatiseren van de implementatie van applicaties in containers, YAML-bestanden worden gebruikt om containers te bouwen en te configureren en andere gerelateerde zaken (bijvoorbeeld netwerken, persistente bestandssystemen voor het opslaan van gegevens).
Het kan ook worden gebruikt om pijplijnen voor CICD te organiseren. Een andere interessante functie is het werken in clustermodus, de zogenaamde zwermmodus (vóór versie 1.12 heette het docker-zwerm), waarmee je een enkele infrastructuur uit verschillende servers kunt samenstellen om containers te laten draaien. Er is ondersteuning voor een virtueel netwerk bovenop alle servers, er is een ingebouwde load balancer, evenals ondersteuning voor geheimen voor containers.
De YAML-bestanden van docker compose kunnen met kleine aanpassingen voor dergelijke clusters worden gebruikt, waardoor het onderhoud van kleine en middelgrote clusters voor verschillende doeleinden volledig wordt geautomatiseerd. Voor grote clusters heeft Kubernetes de voorkeur omdat de onderhoudskosten van de zwermmodus hoger kunnen zijn dan die van Kubernetes. Naast runC kun je als uitvoeringsomgeving voor containers bijvoorbeeld installeren
Werken met Docker
Na installatie en configuratie gaan we proberen een cluster te bouwen waarin we GitLab en Docker Registry gaan inzetten voor het ontwikkelteam. Als servers zal ik drie virtuele machines gebruiken, waarop ik bovendien de door GlusterFS gedistribueerde FS zal implementeren, ik zal het gebruiken als docker-volumeopslag, bijvoorbeeld om een faalveilige versie van het docker-register uit te voeren. Belangrijkste componenten om uit te voeren: Docker Registry, Postgresql, Redis, GitLab met ondersteuning voor GitLab Runner bovenop Swarm. Postgresql wordt gelanceerd met clustering
Om GlusterFS op alle servers te implementeren (ze worden node1, node2, node3 genoemd), moet u pakketten installeren, de firewall inschakelen en de benodigde mappen maken:
# 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/fstab
Na installatie moet het werk aan het configureren van GlusterFS worden voortgezet vanaf één knooppunt, bijvoorbeeld knooppunt1:
# 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 docker
Vervolgens moet u het resulterende volume koppelen (de opdracht moet op alle servers worden uitgevoerd):
# mount /srv/docker
De zwermmodus is geconfigureerd op een van de servers, die leider zal zijn, de rest moet lid worden van het cluster, dus het resultaat van het uitvoeren van de opdracht op de eerste server moet worden gekopieerd en uitgevoerd op de rest.
Initiële clusterconfiguratie, ik voer de opdracht uit op knooppunt1:
# 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 manager
Kopieer het resultaat van de tweede opdracht, voer uit op knooppunt2 en knooppunt3:
# docker swarm join --token SWMTKN-x-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxx xx.xx.xx.xx:2377
This node joined a swarm as a manager.
Dit voltooit de voorlopige configuratie van de servers, laten we beginnen met het configureren van de services, de uit te voeren opdrachten worden gestart vanaf node1, tenzij anders aangegeven.
Laten we eerst netwerken voor containers maken:
# 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 gitlab
Vervolgens markeren we de servers, dit is nodig om sommige services aan de servers te binden:
# docker node update --label-add nodename=node1 node1
# docker node update --label-add nodename=node2 node2
# docker node update --label-add nodename=node3 node3
Vervolgens maken we mappen voor het opslaan van etcd-gegevens, de KV-opslag die Traefik en Stolon nodig hebben. Net als bij Postgresql zijn dit containers die zijn gebonden aan servers, dus voeren we deze opdracht uit op alle servers:
# mkdir -p /srv/etcd
Maak vervolgens een bestand om etcd te configureren en pas het toe:
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 etcd
Na een tijdje controleren we of het etcd-cluster is gestegen:
# 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 healthy
Maak mappen voor Postgresql, voer de opdracht uit op alle servers:
# mkdir -p /srv/pgsql
Maak vervolgens een bestand om Postgresql te configureren:
01pgsql.yml
version: '3.7'
services:
pgsentinel:
image: sorintlab/stolon:master-pg10
command:
- 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
networks:
- etcd
- pgsql
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 30s
order: stop-first
failure_action: pause
pgkeeper1:
image: sorintlab/stolon:master-pg10
hostname: pgkeeper1
command:
- 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
networks:
- etcd
- pgsql
environment:
- PGDATA=/var/lib/postgresql/data
volumes:
- pgkeeper1:/var/lib/postgresql/data
secrets:
- pgsql
- pgsql_repl
deploy:
replicas: 1
placement:
constraints: [node.labels.nodename == node1]
pgkeeper2:
image: sorintlab/stolon:master-pg10
hostname: pgkeeper2
command:
- 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
networks:
- etcd
- pgsql
environment:
- PGDATA=/var/lib/postgresql/data
volumes:
- pgkeeper2:/var/lib/postgresql/data
secrets:
- pgsql
- pgsql_repl
deploy:
replicas: 1
placement:
constraints: [node.labels.nodename == node2]
pgkeeper3:
image: sorintlab/stolon:master-pg10
hostname: pgkeeper3
command:
- 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
networks:
- etcd
- pgsql
environment:
- PGDATA=/var/lib/postgresql/data
volumes:
- pgkeeper3:/var/lib/postgresql/data
secrets:
- pgsql
- pgsql_repl
deploy:
replicas: 1
placement:
constraints: [node.labels.nodename == node3]
postgresql:
image: sorintlab/stolon:master-pg10
command: 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
networks:
- etcd
- pgsql
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 30s
order: stop-first
failure_action: rollback
volumes:
pgkeeper1:
driver: local
driver_opts:
type: none
o: bind
device: "/srv/pgsql"
pgkeeper2:
driver: local
driver_opts:
type: none
o: bind
device: "/srv/pgsql"
pgkeeper3:
driver: local
driver_opts:
type: none
o: bind
device: "/srv/pgsql"
secrets:
pgsql:
file: "/srv/docker/postgres"
pgsql_repl:
file: "/srv/docker/replica"
networks:
etcd:
external: true
pgsql:
external: true
We genereren geheimen, passen 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 pgsql
Enige tijd later (kijk naar de uitvoer van het commando docker-service lsdat alle services zijn gestegen) initialiseer het 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 init
De gereedheid van het Postgresql-cluster controleren:
# 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 om de toegang tot containers van buitenaf te openen:
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 traefik
We starten Redis Cluster, hiervoor maken we een opslagmap op alle knooppunten:
# mkdir -p /srv/redis
05redis.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 <<EOF > /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 redis
Docker-register toevoegen:
06register.yml
version: '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 registry
En tot slot - GitLab:
08gitlab-runner.yml
version: '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'] = "[email protected]"
gitlab_rails['smtp_password'] = "xxxxxxxxx"
gitlab_rails['smtp_domain'] = "example.com"
gitlab_rails['gitlab_email_from'] = '[email protected]'
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 gitlab
De uiteindelijke status van het cluster en de 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/tcp
Wat kan er nog verbeterd worden? Zorg ervoor dat u Traefik configureert om met https-containers te werken, voeg tls-codering toe voor Postgresql en Redis. Maar over het algemeen kun je het al als PoC aan ontwikkelaars geven. Laten we nu kijken naar alternatieven voor Docker.
podman
Een andere redelijk bekende engine voor het uitvoeren van containers gegroepeerd op pods (pods, groepen containers die samen worden ingezet). In tegenstelling tot Docker heeft het geen service nodig om containers uit te voeren, al het werk wordt gedaan via de libpod-bibliotheek. Ook geschreven in Go, heeft een OCI-compatibele runtime nodig om containers zoals runC uit te voeren.
Werken met Podman lijkt in het algemeen op dat van Docker, voor zover je het zo kunt doen (beweerd door velen die het hebben geprobeerd, waaronder de auteur van dit artikel):
$ alias docker=podman
en je kunt blijven werken. Over het algemeen is de situatie met Podman erg interessant, want als de vroege versies van Kubernetes met Docker werkten, dan sinds ongeveer 2015, na de standaardisatie van de containerwereld (OCI - Open Container Initiative) en de scheiding van Docker in containerd en runC , wordt er een alternatief voor Docker ontwikkeld om in Kubernetes te draaien: CRI-O. Podman is in dit opzicht een alternatief voor Docker, gebouwd op de principes van Kubernetes, inclusief containergroepering, maar het belangrijkste doel van het project is om Docker-achtige containers te gebruiken zonder aanvullende services. Om voor de hand liggende redenen is er geen zwermmodus, aangezien de ontwikkelaars duidelijk zeggen dat als je een cluster nodig hebt, je Kubernetes moet nemen.
installatie
Om op Centos 7 te installeren, activeert u gewoon de Extras-repository en installeert u vervolgens alles met de opdracht:
# yum -y install podman
Andere functies
Podman kan eenheden voor systemd genereren, waardoor het probleem van het starten van containers na het opnieuw opstarten van een server wordt opgelost. Bovendien wordt verklaard dat systemd correct werkt als pid 1 in de container. Om containers te bouwen, is er een aparte buildah-tool, er zijn ook tools van derden - analogen van docker-compose, die ook Kubernetes-compatibele configuratiebestanden genereert, dus de overgang van Podman naar Kubernetes is zo eenvoudig mogelijk.
Werkt bij Podman
Aangezien er geen zwermmodus is (het wordt verondersteld over te schakelen naar Kubernetes als er een cluster nodig is), zullen we het in aparte containers assembleren.
Podman-compose installeren:
# yum -y install python3-pip
# pip3 install podman-compose
Het resulterende configuratiebestand voor podman is iets anders, omdat we bijvoorbeeld een aparte volumessectie rechtstreeks naar de servicessectie moesten verplaatsen.
gitlab-podman.yml
version: '3.7'
services:
gitlab:
image: 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:
image: 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
networks:
gitlab:
# podman-compose -f gitlab-runner.yml -d up
Resultaat werk:
# 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_1
Laten we eens kijken wat het zal genereren voor systemd en kubernetes, hiervoor moeten we de naam of id van de pod weten:
# podman pod ls
POD ID NAME STATUS CREATED # OF CONTAINERS INFRA ID
71fc2b2a5c63 root Running 11 minutes ago 3 db40ab8bf84b
Kubernetes:
# 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: {}
systeemd:
# 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
Helaas doet de gegenereerde unit voor systemd behalve het opstarten van containers niets anders (bijvoorbeeld oude containers opschonen als zo'n service opnieuw wordt opgestart), dus dergelijke dingen zul je zelf moeten toevoegen.
Podman is in principe voldoende om te proberen wat containers zijn, oude configuraties over te dragen voor docker-compose en vervolgens, indien nodig, richting Kubernetes op een cluster te gaan, of een gebruiksvriendelijker alternatief voor Docker te krijgen.
RKT
Project
Plas
Meer
Bevindingen
De situatie met Kubernetes is erg interessant: aan de ene kant kun je met Docker een cluster samenstellen (in zwermmodus), waarmee je zelfs productieomgevingen voor klanten kunt draaien, dit geldt vooral voor kleine teams (3-5 personen ), of met een kleine totale belasting, of het gebrek aan verlangen om de fijne kneepjes van het opzetten van Kubernetes te begrijpen, ook voor hoge belastingen.
Podman biedt geen volledige compatibiliteit, maar heeft één belangrijk voordeel: compatibiliteit met Kubernetes, inclusief extra tools (buildah en andere). Daarom zal ik de keuze van een tool voor werk als volgt benaderen: voor kleine teams, of met een beperkt budget - Docker (met een mogelijke zwermmodus), voor ontwikkeling voor mezelf op een persoonlijke localhost - Podman-kameraden, en voor alle anderen - Kubernetes.
Ik weet niet zeker of de situatie met Docker in de toekomst niet zal veranderen, ze zijn tenslotte pioniers en standaardiseren ook langzaam stap voor stap, maar Podman, met al zijn tekortkomingen (werkt alleen op Linux, er is geen clustering , montage en andere acties zijn beslissingen van derden) de toekomst is duidelijker, dus ik nodig iedereen uit om deze bevindingen in de commentaren te bespreken.
PS Op 3 augustus lanceren we "
Pre-orderkosten vóór release: 5000 roebel. Het programma "Docker Video Cursus" is te vinden
Bron: www.habr.com