Docker an alles, alles, alles

TL;DR: En Iwwerbléckguide fir Kaderen ze vergläichen fir Uwendungen a Container ze lafen. D'Kapazitéite vum Docker an aner ähnlech Systemer ginn berücksichtegt.

Docker an alles, alles, alles

Eng kleng Geschicht vu wou et alles hierkënnt

Geschicht

Déi éischt bekannte Method fir eng Applikatioun ze isoléieren ass Chroot. De Systemruff mam selwechten Numm garantéiert datt de Root-Verzeichnis geännert gëtt - also garantéiert datt de Programm deen et genannt huet nëmmen Zougang zu Dateien an deem Verzeichnis huet. Awer wann e Programm intern root Privilegien gëtt, kann et potenziell de Chroot "entkommen" an Zougang zum Haaptbetribssystem kréien. Zousätzlech fir de Root-Verzeichnis z'änneren, sinn aner Ressourcen (RAM, Prozessor), souwéi Netzzougang net limitéiert.

Déi nächst Method ass e vollwäertege Betribssystem an engem Container ze starten, mat de Mechanismen vum Betribssystemkär. Dës Method gëtt anescht a verschiddene Betribssystemer genannt, awer d'Essenz ass d'selwecht - e puer onofhängeg Betribssystemer lancéieren, jidderee leeft deeselwechte Kernel op deem den Haaptbetribssystem leeft. Dozou gehéieren FreeBSD Jails, Solaris Zonen, OpenVZ an LXC fir Linux. D'Isolatioun gëtt net nëmmen duerch Disk Space gesuergt, awer och duerch aner Ressourcen; besonnesch all Container kann Aschränkungen op Prozessor Zäit, RAM an Netzwierkbandbreedung hunn. Am Verglach mam Chroot ass de Container méi schwéier ze verloossen, well de Superuser am Container nëmmen Zougang zum Inhalt vum Container huet, awer wéinst der Bedierfnes fir de Betribssystem am Container um neiste Stand ze halen an d'Benotzung vun eelere Versiounen vu Kernelen (relevant fir Linux, a mannerem Ausmooss FreeBSD), gëtt et eng net Null d'Wahrscheinlechkeet fir de Kernelisolatiounssystem ze "duerchbriechen" an Zougang zum Haaptbetribssystem ze kréien.

Amplaz e vollwäertege Betribssystem an engem Container ze lancéieren (mat engem Initialiséierungssystem, Package Manager, asw.), kënnt Dir Applikatiounen direkt starten, den Haapt Saach ass d'Applikatiounen esou eng Chance ze bidden (d'Präsenz vun den néidege Bibliothéiken an aner Dateien). Dës Iddi huet als Basis fir containeriséierter Applikatiounsvirtualiséierung gedéngt, dee prominentsten a bekanntste Vertrieder vun deem Docker ass. Am Verglach mat fréiere Systemer, méi flexibel Isolatiounsmechanismen, gekoppelt mat agebauter Ënnerstëtzung fir virtuell Netzwierker tëscht Container an Applikatiounszoustand Tracking am Container, hunn d'Fäegkeet gefouert fir en eenzegt kohärent Ëmfeld aus enger grousser Zuel vu kierperleche Servere fir Container ze bauen - ouni de Besoin fir manuell Ressource Gestioun.

Docker

Docker ass déi bekanntst Applikatioun Containeriséierungssoftware. Geschriwwen an der Go Sprooch, benotzt et d'Standardfeatures vum Linux Kernel - cgroups, Namespaces, Capabilities, etc., souwéi Aufs Dateisystemer an anerer wéi dat fir Disk Space ze spueren.

Docker an alles, alles, alles
Source: Wikimedia

Architektur

Virun Versioun 1.11 huet Docker als eenzegen Service geschafft, deen all Operatioune mat Container duerchgefouert huet: Biller fir Container eroflueden, Container starten, API-Ufroen veraarbecht. Vun der Versioun 1.11 un, gouf Docker an e puer Deeler opgedeelt, déi matenee interagéieren: Containerd, fir de ganze Liewenszyklus vu Container ze veraarbechten (Disc Plaz verdeelen, Biller eroflueden, mam Netz schaffen, starten, installéieren an iwwerwaachen den Zoustand vun de Container) an runC, d'Container-Ausféierungsëmfeld, baséiert op der Benotzung vu cgroups an aner Features vum Linux Kernel. Den Docker Service selwer bleift, awer elo déngt et nëmmen fir API Ufroen ze veraarbecht, déi op Containerd iwwersat ginn.

Docker an alles, alles, alles

Installatioun a Konfiguratioun

Mäi Liiblings Wee fir Docker z'installéieren ass Docker-Maschinn, déi, nieft dem direkten Installatioun an der Konfiguratioun vum Docker op Fernserveren (inklusiv verschidde Wolleken), et méiglech mécht mat Dateiesystemer vu Fernserveren ze schaffen an och verschidde Kommandoen auszeféieren.

Wéi och ëmmer, zënter 2018 ass de Projet kaum entwéckelt ginn, sou datt mir et op de Standard Manéier fir déi meescht Linux Verdeelungen installéieren - e Repository derbäisetzen an déi néideg Packagen installéieren.

Dës Method gëtt och fir automatiséiert Installatioun benotzt, zum Beispill mat Ansible oder aner ähnlech Systemer, awer ech wäert et net an dësem Artikel betruechten.

D'Installatioun gëtt op Centos 7 duerchgefouert, ech benotze eng virtuell Maschinn als Server, fir z'installéieren just d'Befehle hei ënnen:

# 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

No der Installatioun musst Dir de Service starten an en an de Startup setzen:

# systemctl enable docker
# systemctl start docker
# firewall-cmd --zone=public --add-port=2377/tcp --permanent

Zousätzlech kënnt Dir en Docker-Grupp erstellen, deem seng Benotzer fäeg sinn ouni Sudo mam Docker ze schaffen, Logbicher opzestellen, Zougang zu der API vu baussen z'erméiglechen, a vergiesst net d'Firewall méi präzis ze konfiguréieren (alles wat net erlaabt ass) ass an de Beispiller uewen an ënnen verbueden - ech hunn dëst fir Simplicitéit a Kloerheet ausgelooss), awer ech ginn net méi an Detailer hei.

Aner Funktiounen

Zousätzlech zu der uewen ernimmt Docker Maschinn gëtt et och Docker Registry, e Tool fir Biller fir Container ze späicheren, souwéi Docker compose, e Tool fir d'Deployment vun Uwendungen an Containeren ze automatiséieren, YAML Dateien gi benotzt fir Container ze bauen an ze konfiguréieren an aner Zesummenhang Saachen (Zum Beispill, Netzwierker, persistent Fichier Systemer fir Stockage Daten).

Et kann och benotzt ginn fir conveyors fir CICD ze organiséieren. Eng aner interessant Feature funktionnéiert am Clustermodus, de sougenannte Schwarmmodus (virun der Versioun 1.12 war et als Docker-Schwarm bekannt), wat Iech erlaabt eng eenzeg Infrastruktur vu verschiddene Serveren ze sammelen fir Container ze lafen. Et gëtt Ënnerstëtzung fir e virtuellt Netzwierk uewen op all Server, et gëtt en agebaute Lastbalancer, souwéi Ënnerstëtzung fir Geheimnisser fir Container.

YAML Dateien aus Docker compose, mat klengen Ännerungen, kënne fir sou Cluster benotzt ginn, komplett automatiséiert den Ënnerhalt vu klengen a mëttelgrousse Cluster fir verschidden Zwecker. Fir grouss Stärekéip ass Kubernetes léiwer well d'Ënnerhaltskäschte vum Schwarmmodus kënnen déi vu Kubernetes iwwerschreiden. Zousätzlech zu runC kënnt Dir zum Beispill als Container Ausféierungsëmfeld installéieren Kata Container

Schafft mat Docker

No der Installatioun an der Konfiguratioun probéieren mir e Cluster ze sammelen an deem mir GitLab an Docker Registry fir d'Entwécklungsteam ofsetzen. Ech wäert dräi virtuell Maschinnen als Server benotzen, op deenen ech zousätzlech déi verdeelt FS GlusterFS ofsetzen; Ech wäert et als Docker Volumen Späichere benotzen, zum Beispill, fir eng Feelertolerant Versioun vum Docker Registry ze lafen. Schlësselkomponenten fir ze lafen: Docker Registry, Postgresql, Redis, GitLab mat Ënnerstëtzung fir GitLab Runner uewen op Swarm. Mir starten Postgresql mat Clustering Stolon, also braucht Dir net GlusterFS ze benotzen fir Postgresql Daten ze späicheren. Déi reschtlech kritesch Donnéeën ginn op GlusterFS gespäichert.

Fir GlusterFS op all Server z'installéieren (si ginn node1, node2, node3 genannt), musst Dir Packagen installéieren, d'Firewall aktivéieren an déi néideg Verzeichnisser erstellen:

# 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

No der Installatioun muss d'Aarbecht un der Konfiguratioun vu GlusterFS vun engem Node weidergefouert ginn, zum Beispill 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 docker

Da musst Dir de resultéierende Volume montéieren (de Kommando muss op all Server ausgefouert ginn):

# mount /srv/docker

De Schwarmmodus ass op engem vun de Serveren konfiguréiert, deen de Leader wäert sinn, de Rescht muss de Cluster bäitrieden, sou datt d'Resultat vum Kommando op den éischte Server muss kopéiert an op deenen aneren ausgefouert ginn.

Initial Cluster Setup, ech lafen de Kommando 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 manager

Mir kopéieren d'Resultat vum zweete Kommando an ausféieren et op Node2 an Node3:

# docker swarm join --token SWMTKN-x-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxx xx.xx.xx.xx:2377
This node joined a swarm as a manager.

Zu dësem Zäitpunkt ass déi virleefeg Konfiguratioun vun de Serveren ofgeschloss, loosst eis weidergoen fir d'Servicer opzestellen; d'Befehle fir auszeféieren ginn vum Node1 gestart, wann net anescht uginn.

Als éischt, loosst eis Netzwierker fir Container erstellen:

# 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

Da markéiere mir d'Serveren, dëst ass néideg fir e puer Servicer un d'Serveren ze 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

Als nächst erstelle mir Verzeichnisser fir etcd Daten ze späicheren, KV Späicheren, déi fir Traefik a Stolon gebraucht ginn. Ähnlech wéi Postgresql, wäerten dës Container mat Serveren gebonne sinn, sou datt mir dëse Kommando op all Server lafen:

# mkdir -p /srv/etcd

Als nächst erstellt eng Datei fir etcd ze konfiguréieren a benotzt se:

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

No enger Zäit kontrolléiere mir datt den etcd Cluster erop ass:

# 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

Mir erstellen Verzeichnisser fir Postgresql, fuert de Kommando op all Server aus:

# mkdir -p /srv/pgsql

Als nächst erstellt eng Datei fir Postgresql ze konfiguréieren:

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

Mir generéieren Geheimnisser a benotzen d'Datei:

# </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

No enger Zäit (kuckt d'Ausgab vum Kommando docker service lsdatt all Servicer erop sinn) initialiséieren mir 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 init

Iwwerpréift d'Bereetschaft vum 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

Mir konfiguréieren Traefik fir Zougang zu Container vu baussen opzemaachen:

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

Mir starten Redis Cluster, fir dëst ze maachen erstellen mir e Späicherverzeechnes op all Noden:

# 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

Add Docker Registry:

06registry.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

A schliisslech - 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

Den definitiven Zoustand vum Cluster a Servicer:

# 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 kann nach verbessert ginn? Gitt sécher Traefik ze konfiguréieren fir Container iwwer https ze lafen, add tls Verschlësselung fir Postgresql a Redis. Awer am Allgemengen kann et scho fir Entwéckler als PoC ginn. Loosst eis elo Alternativen zum Docker kucken.

podman

En anere zimmlech bekannte Motor fir Container ze bedreiwen, gruppéiert vu Pods (Pods, Gruppe vu Container déi zesummen agesat ginn). Am Géigesaz zu Docker erfuerdert et kee Service fir Container ze lafen; all Aarbecht gëtt duerch d'libpod Bibliothéik gemaach. Och am Go geschriwwen, erfuerdert eng OCI-kompatibel Runtime fir Container ze lafen, wéi runC.

Docker an alles, alles, alles

Mat Podman ze schaffen erënnert allgemeng un dat fir Docker, bis zum Punkt datt Dir et esou maache kënnt (wéi gesot vu villen déi et probéiert hunn, och den Auteur vun dësem Artikel):

$ alias docker=podman

an Dir kënnt weider schaffen. Am Allgemengen ass d'Situatioun mam Podman ganz interessant, well wann fréi Versioune vu Kubernetes mat Docker geschafft hunn, dann ëm 2015, no der Standardiséierung vun der Welt vu Container (OCI - Open Container Initiative) an der Divisioun vum Docker an Containerd a RunC, eng Alternativ zum Docker fir a Kubernetes ze lafen ass entwéckelt: CRI-O. Podman an dëser Hisiicht ass eng Alternativ zu Docker, gebaut op de Prinzipien vu Kubernetes, inklusiv Gruppéierungsbehälter, awer den Haaptzweck vum Projet ass Docker-Stil Container ouni zousätzlech Servicer ze lancéieren. Aus offensichtleche Grënn gëtt et kee Schwarmmodus, well d'Entwéckler kloer soen datt wann Dir e Stärekoup braucht, huelt Kubernetes.

Kader

Fir op Centos 7 z'installéieren, aktivéiert just den Extras Repository, an installéiert dann alles mam Kommando:

# yum -y install podman

Aner Funktiounen

Podman kann Unitéiten fir Systemd generéieren, sou datt de Problem vum Startbehälter no engem Server Neistart léist. Zousätzlech gëtt systemd deklaréiert fir richteg als Pid 1 am Container ze schaffen. Et gëtt e separat buildah-Tool fir Container ze bauen, et ginn och Drëtt-Partei-Tools - Analoge vum Docker-compose, déi och Konfiguratiounsdateien generéieren, déi mat Kubernetes kompatibel sinn, sou datt den Iwwergank vu Podman op Kubernetes sou vill wéi méiglech vereinfacht gëtt.

Schafft mat Podman

Well et kee Schwarmmodus gëtt (mir sollen op Kubernetes wiesselen wann e Cluster gebraucht gëtt), sammele mir et an getrennten Container.

Installéiert podman-compose:

# yum -y install python3-pip
# pip3 install podman-compose

Déi resultéierend Konfiguratiounsdatei fir Podman ass liicht anescht, also hu mir zum Beispill eng separat Volumen Sektioun direkt an d'Sektioun mat Servicer réckelen.

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

Resultat:

# 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

Loosst eis kucken wat et fir systemd a kubernetes generéiert, dofir musse mir den Numm oder d'ID vum Pod erausfannen:

# 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: {}

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

Leider, ausser d'Behälter lancéieren, mécht déi generéiert Eenheet fir systemd näischt anescht (zum Beispill al Container botzen wann esou e Service nei gestart gëtt), also musst Dir esou Saachen selwer schreiwen.

Am Prinzip ass Podman genuch fir ze probéieren wat Container sinn, al Konfiguratioune fir Docker-compose ze transferéieren, an dann a Richtung Kubernetes réckelen, wann Dir e Cluster braucht, oder eng méi einfach ze benotzen Alternativ zum Docker kréien.

rkt

De Projet an d'Archiv gaangen virun ongeféier sechs Méint wéinst der Tatsaach, datt RedHat et kaaft huet, also wäert ech net méi am Detail ophalen. Am Allgemengen huet et e ganz gudden Androck hannerlooss, awer am Verglach zum Docker a besonnesch Podman gesäit et aus wéi eng Kombinatioun. Et gouf och eng CoreOS Verdeelung uewen op rkt gebaut (och wann se ursprénglech Docker haten), awer dëst ass och an der Ënnerstëtzung nom RedHat Kaf opgehalen.

Plaatz

Méi engem Projet, den Auteur vun deem just Container wollt bauen a lafen. No der Dokumentatioun an de Code beurteelen, huet den Auteur net d'Standarden gefollegt, awer einfach decidéiert seng eegen Ëmsetzung ze schreiwen, wat hien am Prinzip gemaach huet.

Conclusiounen

D'Situatioun mat Kubernetes ass ganz interessant: Engersäits, mat Docker kënnt Dir e Cluster bauen (am Schwarmmodus), mat deem Dir souguer Produktëmfeld fir Clienten ausféiere kënnt, dëst ass besonnesch wouer fir kleng Teams (3-5 Leit) , oder mat enger klenger Gesamtbelaaschtung, oder Mangel u Wonsch fir d'Intricacies vun der Opstellung vu Kubernetes ze verstoen, och fir héich Lasten.

Podman bitt keng voll Kompatibilitéit, awer et huet ee wichtege Virdeel - Kompatibilitéit mat Kubernetes, och zousätzlech Tools (buildah an anerer). Dofir wäert ech d'Wiel vun engem Tool fir Aarbecht wéi follegt Approche: fir kleng Équipen, oder mat engem limitéierten Budget - Docker (mat engem méigleche Schwarmmodus), fir mech selwer op engem perséinleche localhost z'entwéckelen - Podman Komeroden, a fir all aner - Kubernetes.

Ech sinn net sécher datt d'Situatioun mam Docker sech an Zukunft net ännert, schliisslech si se Pionéier, a ginn och lues a lues standardiséiert, Schrëtt fir Schrëtt, awer Podman, fir all seng Mängel (schafft nëmmen op Linux, kee Clustering, Assemblée an aner Aktiounen sinn Drëtt Partei Léisungen) d'Zukunft ass méi kloer, also ech invitéieren jiddereen dës Erkenntnisser an de Kommentaren ze diskutéieren.

PS Den 3. August lancéiere mir “Docker Video Course", wou Dir méi iwwer seng Aarbecht léiere kënnt. Mir analyséieren all seng Tools: vu Basisabstraktiounen bis Netzwierkparameter, Nuancen vun der Aarbecht mat verschiddene Betribssystemer a Programméierungssproochen. Dir wäert mat der Technologie vertraut ginn a verstinn wou a wéi Dir am Beschten Docker benotzt. Mir wäerten och Best Practice Fäll deelen.

Pre-Order Präis virum Verëffentlechung: RUB 5000. Dir kënnt den Docker Video Course Programm kucken op der Course Säit.

Source: will.com

Setzt e Commentaire