Docker ja kõik, kõik, kõik

TL;DR: ülevaate-artikkel rakenduste konteinerites käivitamise keskkondade võrdlemiseks. Käsitletakse Dockerit ja teisi sarnaseid süsteeme.

Docker ja kõik, kõik, kõik

Veidi ajaloost, kust kõik alguse sai

Ajalugu

Esimene tuntud rakenduse isoleerimise meetod on chroot. See sama süsteemi kutsung muudab juurkatalooge - võimaldades programmil, mis seda kutsub, juurdepääsu ainult selle katalooge sisesisene failidele. Kuid kui programmile antakse superkasutaja õigused, võib see potentsiaalselt "põgeneda" chrootist ja saada juurdepääsu põhikirjale. Samuti ei piirduta juurkatalooge vahetusega teiste ressursside (mälu, protsessor) ning võrgujuurdepääsuga.

Järgmiseks meetodiks on täisfunktsionaalse operatsioonisüsteemi käitamine konteineri sees, operatsioonisüsteemi tuumamehhanismide abil. Erinevates operatsioonisüsteemides nimetatakse seda meetodit erinevalt, kuid põhimõte jääb samaks - mitme sõltumatu operatsioonisüsteemi käitamine, millest igaühel on juure tuum, millel põhikirjarežiim töötab. Siia kuuluvad FreeBSD Jails, Solaris Zones, OpenVZ ja LXC Linuxile. Tagatakse isoleeritus mitte ainult ketta ruumi, vaid ka teiste ressursside osas, eelkõige võib igal konteineril olla piirangud protsessorinõuete, mälu ja võrgu ribalaiuste osas. Võrreldes chrootiga on konteinerist väljapääsemine keerulisem, kuna konteineri superkasutajal on juurdepääs ainult konteineri sisule, kuid vajadusest hoida konteerimine ajakohasena ja kasutada vanu tuumaversioone (mis on aktuaalne Linuxile, vähem FreeBSD-le) on olemas tõenäosus "tuuma isoleerimisest läbi murda" ja saada juurdepääs põhikirjale.

Kuna allalaadimist täis operatsioonisüsteemi konteineris (käivitus süsteemi, pakettide haldamine jne) on võimalik kohe käivitada rakendusi, peamine on tagada rakendustele selliste funktsioonide olemasolu (vajalikud teegid ja muud failid). See idee sai alusena rakenduste konteinerite virtualiseerimisele, mille kõige tuntum ja laiemalt tunnustatud esindaja on Docker. Võrreldes varasemate süsteemidega võimaldasid paindlikumad isolatsioonimehhanismid koos konteinerite vahelise virtuaalsete võrkude sisseehitatud toega ja rakenduste oleku jälgimisega loobuda füüsiliste serverite käsitsi haldamisest, et luua suur hulk konteinerite keskkondi.

Docker

Docker on kõige tuntum rakenduste konteinerimise tarkvara. Kirjutatud Go keeles, kasutab see Linuxi kernel'i sisseehitatud funktsioone — cgroups, namespaces, capabilities jne., samuti failisüsteeme Aufs ja teisi sarnaseid, et säästa kettaruumi.

Docker ja kõik, kõik, kõik
Allikas: wikimedia

Arhitektuur

Enne versiooni 1.11 töötas Docker ühe teenusena, mis teostas kõik konteinerite toimingud: kuvamine konteinerite pilte, konteinerite käivitamine ja API päringute töötlemine. Alates versioonist 1.11 on Docker jagatud mitmeks osaks, mis suhtlevad omavahel: containerd, et hallata konteinerite kogu elutsüklit (ketta ruumi eraldamine, piltide allalaadimine, võrgu haldamine, käivitamine, paigaldamine ja jälgimine) ja runC, konteinerite täitmise keskkond, mis põhineb cgroups'i ja teiste Linuxi kernel'i funktsioonide kasutamisel. Ise teenus docker jäi alles, kuid nüüd see teenib ainult API päringute töötlemiseks, mis edastatakse containerd.

Docker ja kõik, kõik, kõik

Paigaldamine ja seadistamine

Minu lemmikviis Docker'i paigaldamiseks on docker-machine, mis mitte ainult ei paigalda ja seadista dockerit kaugtöötlusserveritesse (sealhulgas erinevatesse pilvedesse), vaid võimaldab ka töötada kaugtöötlusserverite failisüsteemidega ning käivitada erinevaid käske.

Kuid alates 2018. aastast ei ole projekt peaaegu arenenud, seega teeme paigaldamise ikka enamiku Linux i jaotuste jaoks tavapäraselt — lisame hoidla ja paigaldame vajalikud paketid.

Seda meetodit kasutatakse ka automatiseeritud installimisel, näiteks Ansible'i või teiste sarnaste süsteemide abil, kuid seda ma selles artiklis käsitlema ei hakka.

Installatsioon toimub Centos 7 peal, serverina kasutan virtuaalmasinat; piisab, kui käivitada alltoodud käsud:

# 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

Pärast installi tuleb teenus käivitada ja seadistada automaatselt käivituma:

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

Lisaks on võimalik luua docker'i grupp, mille liikmed saavad töötada dockeriga ilma sudo't kasutamata, seadistada logimist, aktiveerida API välise juurdepääsu ning mitte unustada täiendavalt seadistada tulemüür (keelatud on kõik, mis ei ole lubatud; eelnevalt ja allpool olen seda selguse huvides ajanud), kuid siin ma ei peatu.

Muud võimalused

Lisaks mainitud docker machine'ile on olemas veel docker registry, mis on konteinerite piltide salvestamise vahend, ning docker compose, mis on rakenduste konteinerites juurutamise automatiseerimise vahend, kasutades konteinerite ja muude seotud elementide (nt võrgud, püsivad failisüsteemid andmete salvestamiseks) koostamiseks ja seadistamiseks YAML-faile.

Selle abil saab korraldada ka CICD torustikke. Teine huvitav võimalus on klastrirežiimi töö, nn swarm mode (enne versiooni 1.12 tuntud kui docker swarm), mis võimaldab luua mitmest serverist ühtse infrastruktuuri konteinerite käitamiseks. Toetatakse virtuaalvõrku kõigi serverite üle, on olemas sisseehitatud koormuse tasakaalustaja ning konteineritele on toetatud saladusi.

Docker compose'i YAML-failid võivad väikeste muudatustega olla kasutatavad sellistes klasstrites, automatiseerides täielikult väikeste ja keskmise suurusega klasstrite hooldust erinevatel eesmärkidel. Suuremate klasstrite korral on eelistatud Kubernetes, kuna swarm mode'i hoolduskulud võivad ületada Kubernetes'i omad. Kata containers

Töö Dockeriga

Pärast installimist ja seadistamist proovime luua klastrit, kus paigaldame GitLabi ja Docker Registry arendustiimile. Serveritena kasutan kolme virtuaalmasinat, millele paigaldan ka jaotatud failisüsteemi GlusterFS, mida kasutan docker volumes'i salvestamiseks, näiteks Docker Registry usaldusväärse versiooni käivitamiseks. Käivitamiseks vajalikud põhikomponendid: Docker Registry, Postgresql, Redis, GitLab koos GitLab Runneriga Swarmi peal. Postgresql käivitame klasterdamisega. Stolon, seega ei tohi Postgresql andmete salvestamiseks kasutada GlusterFS-i. Ülejäänud kriitilised andmed salvestatakse GlusterFS-is.

GlusterFS-i paigaldamiseks kõigile serveritele (neid kutsutakse node1, node2, node3) tuleb installida paketid, lubada tulemüüride töö ja luua vajalikud kataloogid:

# 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

Pärast paigaldamist tuleb GlusterFS seadistamist jätkata ühest sõlmest, näiteks node1-st:

# 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

Seejärel tuleb loodud volume monteerida (käsku tuleb täita kõigil serveritel):

# mount /srv/docker

Swarm mode seadistamine toimub ühel serveritest, mis saab juhi (Leader) rolli, teised peavad klastri juurde liituma, seega tuleb esimesel serveril käivitatud käsu väljundi kopeerida ja täita teistes.

Klastri esialgne seadistamine, käivitan käsu node1-l:

# 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

Kopeerime teise käsu väljundi, täidame node2-l ja node3-l:

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

Sellega on serverite esialgne seadistamine lõppenud, alustame teenuste seadistamist, käsud täidetakse node1-l, kui ei ole teisiti märgitud.

Esiteks loome võrgud konteinerite jaoks:

# 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

Seejärel märgime serverid, see on vajalik, et siduda mõned teenused serveritega:

# docker node update --label-add nodename=node1 node1
# docker node update --label-add nodename=node2 node2
# docker node update --label-add nodename=node3 node3

Järgmisena loome kataloogid andmete salvestamiseks etcd-s, KV-pood, mis on vajalik Traefikule ja Stolonile. Sarnaselt Postgresqlile on need serveritega seotud konteinerid, seega täidame selle käsu kõigil serveritel:

# mkdir -p /srv/etcd

Seejärel loome etcd seadistamise faili ja rakendame selle:

00etcd.yml

versioon: '3.7'

teenused:
  etcd1:
    pilt: quay.io/coreos/etcd:latest
    hostinimi: etcd1
    käsk:
      - 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
    võrgud:
      - etcd
    mahud:
      - etcd1vol:/data.etcd
    juhi:
      koopiad: 1
      paigutus:
        piirangud: [node.labels.nodename == node1]
  etcd2:
    pilt: quay.io/coreos/etcd:latest
    hostinimi: etcd2
    käsk:
      - 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
    võrgud:
      - etcd
    mahud:
      - etcd2vol:/data.etcd
    juhi:
      koopiad: 1
      paigutus:
        piirangud: [node.labels.nodename == node2]
  etcd3:
    pilt: quay.io/coreos/etcd:latest
    hostinimi: etcd3
    käsk:
      - 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
    võrgud:
      - etcd
    mahud:
      - etcd3vol:/data.etcd
    juhi:
      koopiad: 1
      paigutus:
        piirangud: [node.labels.nodename == node3]

mahud:
  etcd1vol:
    juht: kohalik
    juht_valikud:
      tüüp: none
      o: bind
      seade: "/srv/etcd"
  etcd2vol:
    juht: kohalik
    juht_valikud:
      tüüp: none
      o: bind
      seade: "/srv/etcd"
  etcd3vol:
    juht: kohalik
    juht_valikud:
      tüüp: none
      o: bind
      seade: "/srv/etcd"

võrgud:
  etcd:
    väline: true

# docker stack deploy --compose-file 00etcd.yml etcd

Mõne aja pärast kontrollime, et etcd klaster on üles tõusnud:

# 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

Loome Postgresql jaoks katalooge, käsk tuleb täita kõigil serveritel:

# mkdir -p /srv/pgsql

Järgmisena loome Postgresql seadistamiseks faili:

01pgsql.yml

versioon: '3.7'

teenused:
  pgsentinel:
    pilt: sorintlab/stolon:master-pg10
    käsk:
      - 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
    võrgud:
      - etcd
      - pgsql
    juurutamine:
      koopiad: 3
      värskenduse_config:
        paralleelsus: 1
        viivitus: 30s
        järjekord: stop-first
        tõrke_toiming: pause
  pgkeeper1:
    pilt: sorintlab/stolon:master-pg10
    hostinimi: pgkeeper1
    käsk:
      - 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
    võrgud:
      - etcd
      - pgsql
    keskkond:
      - PGDATA=/var/lib/postgresql/data
    mahutid:
      - pgkeeper1:/var/lib/postgresql/data
    saladused:
      - pgsql
      - pgsql_repl
    juurutamine:
      koopiad: 1
      paiknemine:
        piirangud: [node.labels.nodename == node1]
  pgkeeper2:
    pilt: sorintlab/stolon:master-pg10
    hostinimi: pgkeeper2
    käsk:
      - 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
    võrgud:
      - etcd
      - pgsql
    keskkond:
      - PGDATA=/var/lib/postgresql/data
    mahutid:
      - pgkeeper2:/var/lib/postgresql/data
    saladused:
      - pgsql
      - pgsql_repl
    juurutamine:
      koopiad: 1
      paiknemine:
        piirangud: [node.labels.nodename == node2]
  pgkeeper3:
    pilt: sorintlab/stolon:master-pg10
    hostinimi: pgkeeper3
    käsk:
      - 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
    võrgud:
      - etcd
      - pgsql
    keskkond:
      - PGDATA=/var/lib/postgresql/data
    mahutid:
      - pgkeeper3:/var/lib/postgresql/data
    saladused:
      - pgsql
      - pgsql_repl
    juurutamine:
      koopiad: 1
      paiknemine:
        piirangud: [node.labels.nodename == node3]
  postgresql:
    pilt: sorintlab/stolon:master-pg10
    käsk: 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
    võrgud:
      - etcd
      - pgsql
    juurutamine:
      koopiad: 3
      värskenduse_config:
        paralleelsus: 1
        viivitus: 30s
        järjekord: stop-first
        tõrke_toiming: rollback

mahutid:
  pgkeeper1:
    draiver: kohalik
    draiver_opts:
      tüüp: none
      o: bind
      seade: "/srv/pgsql"
  pgkeeper2:
    draiver: kohalik
    draiver_opts:
      tüüp: none
      o: bind
      seade: "/srv/pgsql"
  pgkeeper3:
    draiver: kohalik
    draiver_opts:
      tüüp: none
      o: bind
      seade: "/srv/pgsql"

saladused:
  pgsql:
    fail: "/srv/docker/postgres"
  pgsql_repl:
    fail: "/srv/docker/replica"

võrgud:
  etcd:
    väline: tõene
  pgsql:
    väline: tõene

Genereerime saladusi, rakendame faili:

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

Mõne aja pärast (vaatame käsu väljundit docker service ls, et näha, et kõik teenused on üles tõusnud) käivitame Postgresql klastri:

# 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

Kontrollime Postgresql klastri valmisolekut:

# 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

Seadistame traefik'i konteinerite väljast juurdepääsu avamiseks:

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

Käivitame Redis klastrit, selleks loome kõikidesse sõlmedesse salvestuskausta:

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

Lisame Docker Registry:

06registry.yml

versioon: '3.7'

teenused:
  registri:
    pilt: registry:2.6
    võrgud:
      - traefik
    mahts:
      - registry_data:\/var\/lib\/registry
    juurutamine:
      koopiad: 1
      asukoht:
        piirangud: [node.role == manager]
      taaskäivitamispoliitika:
        tingimus: on-failure
      sildid:
        - traefik.enable=true
        - traefik.http.routers.registry.rule=Host(`registry.example.com`)
        - traefik.http.services.registry.loadbalancer.server.port=5000
        - traefik.docker.network=traefik

mahts:
  registry_data:
    draiver: kohalik
    draiveri_valikud:
      tüüp: none
      o: bind
      seade: "\/srv\/docker\/registry"

võrgud:
  traefik:
    väline: true

# mkdir /srv/docker/registry
# docker stack deploy --compose-file 06registry.yml registry

Ja lõpuks — GitLab:

08gitlab-runner.yml

versioon: '3.7'

teenused:
  gitlab:
    pilt: gitlab\/gitlab-ce:latest
    võrgud:
      - pgsql
      - redis
      - traefik
      - gitlab
    portid:
      - 22222:22
    keskkond:
      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
    mahts:
      - gitlab_conf:\/etc\/gitlab
      - gitlab_logs:\/var\/log\/gitlab
      - gitlab_data:\/var\/opt\/gitlab
    juurutamine:
      režiim: replitseeritud
      koopiad: 1
      asukoht:
        piirangud:
        - node.role == manager
      sildid:
        - 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:
    pilt: gitlab\/gitlab-runner:latest
    võrgud:
      - gitlab
    mahts:
      - gitlab_runner_conf:\/etc\/gitlab
      - \/var\/run\/docker.sock:\/var\/run\/docker.sock
    juurutamine:
      režiim: replitseeritud
      koopiad: 1
      asukoht:
        piirangud:
        - node.role == manager

mahts:
  gitlab_conf:
    draiver: kohalik
    draiveri_valikud:
      tüüp: none
      o: bind
      seade: "\/srv\/docker\/gitlab\/conf"
  gitlab_logs:
    draiver: kohalik
    draiveri_valikud:
      tüüp: none
      o: bind
      seade: "\/srv\/docker\/gitlab\/logs"
  gitlab_data:
    draiver: kohalik
    draiveri_valikud:
      tüüp: none
      o: bind
      seade: "\/srv\/docker\/gitlab\/data"
  gitlab_runner_conf:
    draiver: kohalik
    draiveri_valikud:
      tüüp: none
      o: bind
      seade: "\/srv\/docker\/gitlab\/runner"

võrgud:
  pgsql:
    väline: true
  redis:
    väline: true
  traefik:
    väline: true
  gitlab:
    väline: 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

Klastri ja teenuste lõplik olek:

# 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

Mida veel saaks parandada? Oluline on seadistada Traefik konteinerite töötamine https-i kaudu, lisada TLS-krüpteerimine Postgresql-i ja Redis'e jaoks. Aga üldiselt saab seda arendajatele anda PoC-na. Vaatame nüüd Dockerile alternatiive.

Podman

Veel üks üsna tuntud mootor konteinerite käivitamiseks, mis on rühmitatud podide (pods, rühmad koos installitud konteineritest) järgi. Erinevalt Dockerist ei nõua see konteinerite käivitamiseks ühtegi teenust, kogu töö toimub läbi libpod teegi. Samuti on see kirjutatud Go-s ja vajab konteinerite käivitamiseks OCI ühilduvat käitusaja keskkonda, näiteks runC.

Docker ja kõik, kõik, kõik

Töö Podmaniga sarnaneb üldiselt Dockeriga, kuni selleni, et saate teha nii (paljude proovijatena, sealhulgas käesoleva artikli autorina, on seda kinnitatud):

$ alias docker=podman

ja saate jätkata töötamist. Üldiselt on olukord Podmaniga üsna huvitav, kuna varasemad Kubernetes versioonid töötasid Dockeriga, siis umbes alates 2015. aastast, pärast konteinerite maailmas standardimise (OCI - Open Container Initiative) ja Docker'i jagunemist containerd ja runC-ks, areneb Dockerile alternatiiv Kubernetes'e jaoks: CRI-O. Podman on selles suhtes Docker'i alternatiiv, mis põhineb Kubernetes'e põhimõtetel, sealhulgas konteinerite gruppides grupeerimisel, kuid projekti peamine eesmärk on käivitada konteinerid Docker'i stiilis ilma täiendavate teenusteta. Arusaadavatel põhjustel ei ole swarm mode'i, kuna arendajad ütlevad selgelt, et kui vajate klastrit - võtke Kubernetes.

Paigaldamine

CentOS 7-s seadistamiseks piisab Extras repostiivide aktiveerimisest ja seejärel paigaldada kõik käsuga:

# yum -y install podman

Muud võimalused

Podman suudab genereerida süsteemi üksuseid systemd jaoks, lahendades seeläbi konteinerite käivitamise probleemid serveri taaskäivitamisel. Lisaks on väidetud, et systemd töötab korrektselt pid 1-na konteineris. Konteinerite kokkupanekuks on olemas eraldi tööriist buildah, samuti on olemas kolmandate osapoolte tööriistad - Docker-compose'i analoogid, mis genereerivad sealhulgas Kubernetes'ega ühilduvaid konfiguratsioonifaile, nii et üleminek Podmanilt Kubernetes'ile on tehtud võimalikult lihtsaks.

Töö Podmaniga

Kuna swarm mode'i ei ole (oodatakse üleminekut Kubernetes'ile, kui on vaja klastrit) - kogume kogumise ajal eraldi konteinerite kaupa.

Installime podman-compose:

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

Tulemuseks olev konfiguratsioonifail podmani jaoks erineb veidi, näiteks tuli eraldi volume sektsioon otse teenuste sektsiooni üle viia.

gitlab-podman.yml

versioon: '3.7'

teenused:
  gitlab:
    pilt: gitlab/gitlab-ce:latest
    domeen: gitlab.example.com
    taasta: kui ei ole peatatud
    keskkond:
      GITLAB_OMNIBUS_CONFIG: |
        gitlab_rails['gitlab_shell_ssh_port'] = 22222
    sadamad:
      - "80:80"
      - "22222:22"
    mahtu:
      - /srv/podman/gitlab/conf:/etc/gitlab
      - /srv/podman/gitlab/data:/var/opt/gitlab
      - /srv/podman/gitlab/logs:/var/log/gitlab
    võrgud:
      - gitlab

  gitlab-runner:
    pilt: gitlab/gitlab-runner:alpine
    taasta: kui ei ole peatatud
    sõltub:
      - gitlab
    mahtu:
      - /srv/podman/gitlab/runner:/etc/gitlab-runner
      - /var/run/docker.sock:/var/run/docker.sock
    võrgud:
      - gitlab

võrgud:
  gitlab:

# podman-compose -f gitlab-runner.yml -d up

Töö tulemus:

# 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

Vaadakem, mida ta genereerib systemd ja kubernetes'i jaoks, selleks on vaja teada poodi nime või ID-d:

# 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

Kahjuks, peale konteinerite käivitamise, ei tee genereeritud üksus systemd jaoks midagi muud (näiteks vanade konteinerite puhastamist sellise teenuse uuesti käivitamisel), seega sellised asjad tuleb ise juurde kirjutada.

Põhimõtteliselt on Podman piisav, et proovida, mis on konteinerid, viia üle vanad konfiguratsioonid docker-compose'ist, pärast mida liikuda Kubernetes'i suunas, kui on vaja klastrit, või saada lihtsamalt hallatav alternatiiv Docker'ile.

rkt

Projekt viibis arhiivis umbes pool aastat tagasi, kuna selle ostis RedHat, seega ma ei peatu sellel detailselt. Üldiselt jättis see üsna hea mulje, kuid võrreldes Docker'iga ja veel enam Podman'iga, näeb see välja nagu kombain. Samuti eksisteeris CoreOS jaotust, mis oli üles ehitatud rkt põhjal (kuigi neil oli algselt Docker), kuid selle tugi lõppes samuti pärast RedHat'i ostu.

Plash

Veel üks projekt, mille autor soovis lihtsalt koguda ja käivitada konteinerid. Kohtu andmete ja koodi põhjal — autor ei järginud standardeid, vaid otsustas lihtsalt kirjutada oma rakenduse, mida ta põhimõtteliselt ka tegi.

Järeldused

Kubernetes'i olemasolu korral on olukord üsna huvitav: ühelt poolt saab Docker'iga koguda klastrit (swarm režiimis), millega saab isegi klientide toote keskkondi käivitada, see on eriti aktuaalne väikestele meeskondadele (3-5 inimest), või väikese üldkoormuse korral, või kui ei ole soovi süveneda Kubernetes'i seadistamise nüanssidesse, sealhulgas suurte koormustega.

Podman ei taga täit ühilduvust, kuid sellel on üks tähtis eelis — ühilduvus Kubernetesega, sealhulgas lisatööriistade (buildah jne) osas. Seetõttu lähen tööriista valikule nii: väikeste meeskondade või piiratud eelarve jaoks — Docker (võimaliku swarm mode'iga), isiklikuks arenduseks kohalikul localhost'il — Podman koos kolleegidega, ning kõigi teiste jaoks — Kubernetes.

Ma ei ole kindel, et Docker'i olukord tulevikus ei muutu; nad on ikkagi pioneerid ning samas aeglaselt standardiseeruvad. Kuid Podman'il, vaatamata kõigile oma puudustele (töö ainult Linuxil, puuduvad klasterdamise võimalused, koostamine ja muud toimingud — kolmandate osapoolte lahendustega) on tulevik selgem, seega kutsun kõiki huvilisi neid järeldusi arutama kommentaarides.

P.S. 3. augustil käivitame “Videokursuse Dockerist”, kus saab lähemalt tutvuda selle tööga. Läbime kõik selle tööriistad: alates peamistest abstraktsioonidest kuni võrgu parameetriteni, erinevate operatsioonisüsteemide ja programmeerimiskeelte töö nüanssideni. Te tutvute tehnoloogiaga ja saate aru, kus ja kuidas on parim Dockerit kasutada. Jagame ka parimaid praktikaid ja juhtumeid.

Eelneva tellimuse hind enne väljaandmist: 5000 rubla. Videokursuse programmi saab vaadata kursuse lehelt.

Allikas: habr.com

Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster