Dokeris ir viskas, viskas, viskas

TL;DR: apžvalginis straipsnis – vadovas, kaip palyginti programas konteineriuose. Bus svarstomos Docker ir kitų panašių sistemų galimybės.

Dokeris ir viskas, viskas, viskas

Šiek tiek istorijos, iš kur visa tai atsirado

Istorija

Pirmasis gerai žinomas būdas atskirti programą yra chroot. To paties pavadinimo sistemos iškvietimas suteikia pakeitimą šakniniam katalogui – taip suteikiama prieiga prie ją iškvietusios programos, prieiga tik prie šiame kataloge esančių failų. Bet jei programai bus suteiktos supervartotojo teisės, ji gali „pabėgti“ iš chroot ir gauti prieigą prie pagrindinės operacinės sistemos. Taip pat, be šakninio katalogo keitimo, neribojami ir kiti ištekliai (RAM, procesorius), taip pat prieiga prie tinklo.

Kitas būdas yra paleisti visavertę operacinę sistemą konteinerio viduje, naudojant operacinės sistemos branduolio mechanizmus. Šis metodas skirtingose ​​operacinėse sistemose vadinamas skirtingai, tačiau esmė ta pati – veikia kelios nepriklausomos operacinės sistemos, kurių kiekviena veikia tame pačiame branduolyje, kuriame veikia pagrindinė operacinė sistema. Tai apima „FreeBSD Jails“, „Solaris Zones“, „OpenVZ“ ir „LXC“, skirtą „Linux“. Atskyrimas numatytas ne tik vietai diske, bet ir kitiems ištekliams, visų pirma kiekvienam konteineriui gali būti taikomi procesoriaus laiko, RAM, tinklo pralaidumo apribojimai. Palyginti su chroot, išeiti iš konteinerio yra sunkiau, nes konteinerio supervartotojas turi prieigą tik prie konteinerio vidaus, tačiau dėl būtinybės atnaujinti konteinerio operacinę sistemą ir naudojant seną branduolį versijose (tinka Linux, kiek mažiau FreeBSD), tikimybė „pralaužti“ branduolio izoliavimo sistemą ir gauti prieigą prie pagrindinės operacinės sistemos yra ne nulis.

Užuot paleidus visavertę operacinę sistemą konteineryje (su inicijavimo sistema, paketų tvarkykle ir pan.), programas galima paleisti iš karto, svarbiausia yra suteikti programoms tokią galimybę (būtinų bibliotekų ir Kiti failai). Ši idėja buvo konteinerinio programų virtualizavimo pagrindas, kurio ryškiausias ir žinomiausias atstovas yra Docker. Palyginti su ankstesnėmis sistemomis, lankstesni atskyrimo mechanizmai, kartu su integruotu virtualių tinklų tarp konteinerių palaikymu ir programos būsenos nustatymu konteineryje, leido sukurti vieną holistinę aplinką iš daugybės fizinių serverių, kad būtų galima paleisti konteinerius – be jų. rankinio išteklių valdymo poreikis.

dokininkas

„Docker“ yra labiausiai žinoma programų konteinerių talpinimo programinė įranga. Parašyta Go kalba, jame naudojamos įprastos Linux branduolio galimybės – cgroups, vardų erdvės, galimybės ir kt., taip pat Aufs failų sistemos ir kitos panašios vietos diske taupymui.

Dokeris ir viskas, viskas, viskas
Šaltinis: wikimedia

Architektūra

Iki 1.11 versijos Docker dirbo kaip viena paslauga, kuri atliko visas operacijas su konteineriais: atsisiuntė konteinerių vaizdus, ​​paleido konteinerius, apdorojo API užklausas. Nuo 1.11 versijos „Docker“ buvo padalintas į kelias dalis, kurios sąveikauja viena su kita: talpyklą, kad būtų galima valdyti visą konteinerių gyvavimo ciklą (diske vietos paskirstymas, vaizdų atsisiuntimas, tinklo kūrimas, konteinerių paleidimas, diegimas ir stebėjimas) ir runC. , konteinerio vykdymo laikas, pagrįstas cgroups ir kitų Linux branduolio funkcijų naudojimu. Pati docker paslauga išlieka, bet dabar ji skirta tik API užklausoms, transliuojamoms į konteinerius, apdoroti.

Dokeris ir viskas, viskas, viskas

Diegimas ir konfigūravimas

Mano mėgstamiausias būdas įdiegti docker yra docker-machine, kuris, be tiesioginio docker diegimo ir konfigūravimo nuotoliniuose serveriuose (įskaitant įvairius debesis), leidžia dirbti su nuotolinių serverių failų sistemomis, taip pat gali vykdyti įvairias komandas.

Tačiau nuo 2018 metų projektas beveik nevykdomas, todėl jį diegsime įprastu daugumai Linux distribucijos būdų – pridėdami saugyklą ir įdiegdami reikiamus paketus.

Šis metodas taip pat naudojamas automatizuotam diegimui, pavyzdžiui, naudojant Ansible ar kitas panašias sistemas, tačiau šiame straipsnyje to nenagrinėsiu.

Diegimas bus atliktas „Centos 7“, kaip serverį naudosiu virtualią mašiną, norėdami įdiegti, tiesiog paleiskite toliau pateiktas komandas:

# 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

Įdiegę turite paleisti paslaugą, įdėti ją į automatinį įkėlimą:

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

Be to, galite sukurti docker grupę, kurios vartotojai galės dirbti su docker be sudo, nustatyti registravimą, įgalinti prieigą prie API iš išorės, nepamirškite sureguliuoti ugniasienės (viskas, kas neleidžiama, yra draudžiama aukščiau ir toliau pateiktuose pavyzdžiuose – dėl paprastumo ir aiškumo tai praleidau), bet čia daugiau nenagrinėsiu.

Kitos funkcijos

Be aukščiau nurodyto doko įrenginio, taip pat yra dokų registras, konteinerių vaizdų saugojimo įrankis, taip pat dokų kūrimo įrankis - įrankis, skirtas automatizuoti programų diegimą konteineriuose, YAML failai naudojami konteineriams kurti ir konfigūruoti. kiti susiję dalykai (pavyzdžiui, tinklai, nuolatinės failų sistemos duomenims saugoti).

Jis taip pat gali būti naudojamas CICD vamzdynams organizuoti. Dar viena įdomi funkcija – darbas klasterio režimu, vadinamasis spiečiaus režimas (iki 1.12 versijos jis buvo žinomas kaip docker swarm), leidžiantis surinkti vieną infrastruktūrą iš kelių serverių, kad būtų galima paleisti konteinerius. Visų serverių viršuje palaikomas virtualus tinklas, yra įmontuotas apkrovos balansavimo įrankis, taip pat konteinerių paslapčių palaikymas.

YAML failai iš docker compose gali būti naudojami tokiems klasteriams su nedideliais pakeitimais, visiškai automatizuojant mažų ir vidutinių grupių priežiūrą įvairiems tikslams. Didelėms grupėms geriau naudoti Kubernetes, nes spiečių režimo priežiūros išlaidos gali viršyti Kubernetes. Be runC, kaip konteinerių vykdymo aplinką, galite įdiegti, pvz Kata konteineriai

Darbas su Docker

Įdiegę ir sukonfigūravę bandysime sukurti klasterį, kuriame diegsime GitLab ir Docker registrą kūrimo komandai. Kaip serverius naudosiu tris virtualias mašinas, kuriose papildomai diegsiu GlusterFS paskirstytą FS, naudosiu kaip docker tomų saugyklą, pavyzdžiui, paleisti saugią docker registro versiją. Pagrindiniai paleisti komponentai: „Docker Registry“, „Postgresql“, „Redis“, „GitLab“ su „GitLab Runner“ palaikymu „Swarm“ viršuje. Postgresql bus paleistas su klasterizavimu Stolonas, todėl jums nereikia naudoti GlusterFS Postgresql duomenims saugoti. Likę svarbūs duomenys bus saugomi GlusterFS.

Norėdami įdiegti GlusterFS visuose serveriuose (jie vadinami node1, node2, node3), turite įdiegti paketus, įjungti užkardą, sukurti reikiamus katalogus:

# 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

Įdiegę GlusterFS konfigūravimo darbus reikia tęsti iš vieno mazgo, pavyzdžiui, 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

Tada turite prijungti gautą tomą (komandą reikia paleisti visuose serveriuose):

# mount /srv/docker

Swarm režimas sukonfigūruotas viename iš serverių, kuris bus Leader, likusieji turės prisijungti prie klasterio, todėl komandos vykdymo pirmame serveryje rezultatą reikės nukopijuoti ir vykdyti likusiuose.

Pradinė klasterio sąranka, aš paleidžiu komandą 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

Nukopijuojame antrosios komandos rezultatą ir vykdome node2 ir node3:

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

Taip baigiama preliminari serverių konfigūracija, pradėkime konfigūruoti paslaugas, vykdomos komandos bus paleistos iš node1, jei nenurodyta kitaip.

Pirmiausia sukurkime konteinerių tinklus:

# 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

Tada pažymime serverius, tai būtina norint susieti kai kurias paslaugas su serveriais:

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

Tada sukuriame katalogus etcd duomenims saugoti, KV saugyklą, kurios reikia „Traefik“ ir „Stolon“. Panašiai kaip Postgresql, tai bus konteineriai, susieti su serveriais, todėl šią komandą vykdome visuose serveriuose:

# mkdir -p /srv/etcd

Tada sukurkite failą, kad sukonfigūruotumėte etcd, ir pritaikykite jį:

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

Po kurio laiko patikriname, ar veikia etcd klasteris:

# 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

Sukurkite „Postgresql“ katalogus, vykdykite komandą visuose serveriuose:

# mkdir -p /srv/pgsql

Tada sukurkite failą, kad sukonfigūruotumėte Postgresql:

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

Sugeneruojame paslaptis, taikome failą:

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

Po kurio laiko (pažiūrėkite į komandos išvestį dokerių paslauga lskad visos paslaugos veikia) inicijuojame Postgresql klasterį:

# 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

„Postgresql“ klasterio parengties tikrinimas:

# 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

Mes sukonfigūruojame traefik, kad atidarytumėte prieigą prie konteinerių iš išorės:

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

Paleidžiame Redis Cluster, tam sukuriame saugojimo katalogą visuose mazguose:

# 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

Pridėti „Docker“ registrą:

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

Ir galiausiai - 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

Galutinė klasterio ir paslaugų būsena:

# 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

Ką dar galima patobulinti? Būtinai sukonfigūruokite „Traefik“, kad jis veiktų su https konteineriais, pridėkite „tls“ šifravimą „Postgresql“ ir „Redis“. Bet apskritai jau galite duoti kūrėjams kaip PoC. Dabar pažvelkime į „Docker“ alternatyvas.

Podmanas

Kitas gana gerai žinomas variklis, skirtas paleisti konteinerius, sugrupuotus pagal ankštis (ankštes, konteinerių grupes, išdėstytas kartu). Skirtingai nei Docker, konteineriams paleisti nereikia jokių paslaugų, visas darbas atliekamas per libpod biblioteką. Taip pat parašyta Go, reikalingas OCI suderinamas vykdymo laikas, kad būtų galima paleisti konteinerius, tokius kaip runC.

Dokeris ir viskas, viskas, viskas

Darbas su „Podman“ apskritai panašus į „Docker“ darbą tiek, kiek galite tai padaryti taip (teigė daugelis jį išbandžiusių, įskaitant šio straipsnio autorių):

$ alias docker=podman

ir tu gali dirbti toliau. Apskritai situacija su Podman yra labai įdomi, nes jei ankstyvosios Kubernetes versijos dirbo su Docker, tai maždaug nuo 2015 m., standartizavus konteinerių pasaulį (OCI – Open Container Initiative) ir suskaidžius Docker į konteinerį ir runC, atsirado alternatyva „Docker“ kuriamas veikti Kubernetes: CRI-O. „Podman“ šiuo atžvilgiu yra „Docker“ alternatyva, sukurta pagal „Kubernetes“ principus, įskaitant konteinerių grupavimą, tačiau pagrindinis projekto tikslas – paleisti „Docker“ tipo konteinerius be papildomų paslaugų. Dėl akivaizdžių priežasčių nėra spiečiaus režimo, nes kūrėjai aiškiai sako, kad jei jums reikia klasterio, pasiimkite „Kubernetes“.

Montavimas

Norėdami įdiegti „Centos 7“, tiesiog suaktyvinkite „Extras“ saugyklą ir įdiekite viską naudodami komandą:

# yum -y install podman

Kitos funkcijos

„Podman“ gali generuoti „systemd“ vienetus, taip išspręsdama konteinerių paleidimo problemą po serverio perkrovimo. Be to, deklaruojama, kad systemd tinkamai veikia kaip pid 1 konteineryje. Konteineriams kurti yra atskiras buildah įrankis, yra ir trečiųjų šalių įrankių – docker-compose analogų, kurie taip pat generuoja su Kubernetes suderinamus konfigūracijos failus, todėl perėjimas iš Podman į Kubernetes yra kuo paprastesnis.

Darbas su Podmanu

Kadangi spiečiaus režimo nėra (jei reikia klasterio turi persijungti į Kubernetes), tai jį surinksime į atskirus konteinerius.

Įdiekite „podman-compose“:

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

Gautas podman konfigūracijos failas šiek tiek skiriasi, nes, pavyzdžiui, turėjome perkelti atskirą tomų skyrių tiesiai į paslaugų skyrių.

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

Darbo rezultatas:

# 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

Pažiūrėkime, ką jis sugeneruos „systemd“ ir „kubernetes“, tam turime sužinoti podelio pavadinimą arba ID:

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

sistema:

# 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

Deja, išskyrus konteinerių paleidimą, sugeneruotas systemd blokas nieko daugiau nedaro (pvz., išvalo senus konteinerius, kai tokia paslauga paleidžiama iš naujo), todėl tokius dalykus turėsite pridėti patys.

Iš esmės užtenka Podman išbandyti, kas yra konteineriai, perkelti senas konfigūracijas docker-compose ir tada, jei reikia, eiti link Kubernetes į klasterį arba gauti lengviau naudojamą Docker alternatyvą.

rkt

Projektas nukeliavo į archyvą maždaug prieš šešis mėnesius dėl to, kad RedHat jį nusipirko, todėl plačiau apie tai nesigilinsiu. Apskritai paliko labai gerą įspūdį, bet lyginant su Docker, o juo labiau su Podman atrodo kaip kombainas. Taip pat buvo „CoreOS“ paskirstymas, sukurtas ant „rkt“ (nors iš pradžių jie turėjo „Docker“, tačiau tai taip pat baigėsi įsigijus „RedHat“.

Blykstė

Daugiau vienas projektas, kurio autorius tiesiog norėjo statyti ir eksploatuoti konteinerius. Sprendžiant iš dokumentacijos ir kodo, autorius nesilaikė standartų, o tiesiog nusprendė parašyti savo įgyvendinimą, kurį iš esmės ir padarė.

išvados

Situacija su Kubernetes yra labai įdomi: viena vertus, naudojant Docker, galite surinkti klasterį (spiečiaus režimu), su kuriuo netgi galite paleisti gamybines aplinkas klientams, tai ypač pasakytina apie mažas komandas (3-5 žmonės). ), arba esant nedidelei bendrai apkrovai, arba trūkstant noro suprasti „Kubernetes“ nustatymo subtilybes, įskaitant ir didelėms apkrovoms.

„Podman“ neužtikrina visiško suderinamumo, tačiau turi vieną svarbų pranašumą - suderinamumą su „Kubernetes“, įskaitant papildomus įrankius („buildah“ ir kitus). Todėl į įrankį darbui pasirinksiu taip: mažoms komandoms arba turintiems ribotą biudžetą - „Docker“ (su galimu spiečiaus režimu), tobulėjimui sau asmeniniame „localhost“ - „Podman“ draugai ir visiems kitiems - Kubernetes.

Nesu tikras, kad su Docker situacija nepasikeis ateityje, juk jie yra pionieriai, taip pat pamažu žingsnis po žingsnio standartizuojasi, bet Podman su visais savo trūkumais (veikia tik ant Linux, nėra klasterizacijos, surinkimo o kiti veiksmai yra trečiųjų šalių sprendimai) ateitis aiškesnė, todėl kviečiu visus šias išvadas aptarti komentaruose.

PS Rugpjūčio 3 d.Docker vaizdo kursaskur galite daugiau sužinoti apie jo darbą. Išanalizuosime visus jo įrankius: nuo pagrindinių abstrakcijų iki tinklo parametrų, darbo su įvairiomis operacinėmis sistemomis ir programavimo kalbų niuansų. Susipažinsite su technologija ir suprasite, kur ir kaip geriausia naudoti Docker. Taip pat pasidalinsime geriausios praktikos pavyzdžiais.

Išankstinio užsakymo kaina prieš išleidimą: 5000 RUB. Galite peržiūrėti Docker Video Course programą kurso puslapyje.

Šaltinis: www.habr.com

Добавить комментарий