Docker eta guzti, guztiak, guztiak

TL;DR: Edukiontzietan aplikazioak exekutatzeko esparruak alderatzeko ikuspegi orokorra. Dockerren eta antzeko beste sistema batzuen gaitasunak kontuan hartuko dira.

Docker eta guzti, guztiak, guztiak

Dena nondik datorren jakiteko historia txiki bat

Story

Aplikazio bat isolatzeko lehen metodo ezaguna chroot da. Izen bereko sistema-deiak erro-direktorioa aldatzen dela bermatzen du, horrela deitzen duen programak direktorio horretako fitxategietara soilik sarbidea duela ziurtatzen du. Baina programa bati barnean root pribilegioak ematen badio, potentzialki "ihes" dezake chroot-etik eta sistema eragile nagusirako sarbidea lor dezake. Era berean, erro direktorioa aldatzeaz gain, beste baliabide batzuk (RAM, prozesadorea), baita sarerako sarbidea ere, ez dira mugatuak.

Hurrengo metodoa edukiontzi baten barruan sistema eragile oso bat abiarazteko da, sistema eragilearen nukleoaren mekanismoak erabiliz. Metodo honi modu ezberdinean deitzen zaio sistema eragile ezberdinetan, baina funtsa berdina da: hainbat sistema eragile independente abiarazten ditu, eta horietako bakoitzak sistema eragile nagusiak exekutatzen duen nukleo bera exekutatzen du. Horien artean daude FreeBSD Jails, Solaris Zones, OpenVZ eta LXC Linuxerako. Isolamendua diskoko espazioak ez ezik, beste baliabide batzuek ere bermatzen du; bereziki, edukiontzi bakoitzak prozesadorearen denboran, RAMan eta sareko banda zabaleran mugak izan ditzake. Chroot-arekin alderatuta, edukiontzia uztea zailagoa da, edukiontzian dagoen supererabiltzaileak edukiontziaren edukirako sarbidea baitu soilik, hala ere, edukiontzi barruan sistema eragilea eguneratuta eduki beharragatik eta bertsio zaharragoak erabiltzeagatik. nukleoen (Linux-erako garrantzitsua, neurri txikiagoan FreeBSD), nukleoa isolatzeko sistema "hautsi" eta sistema eragile nagusirako sarbidea izateko probabilitatea ez da nulua.

Edukiontzi batean sistema eragile oso bat abiarazi beharrean (hasierako sistema batekin, paketeen kudeatzailearekin, etab.), aplikazioak berehala abiarazi ditzakezu, gauza nagusia aplikazioei aukera hori eskaintzea da (beharrezko liburutegien presentzia). eta beste fitxategi batzuk). Ideia hau edukiontzidun aplikazioen birtualizazioaren oinarri izan zen, eta horien ordezkaririk nabarmenena eta ezagunena Docker da. Aurreko sistemekin alderatuta, isolamendu-mekanismo malguagoak, edukiontzien arteko sare birtualen euskarria integratuta eta edukiontziaren barruan aplikazio-egoeraren jarraipenarekin batera, edukiontziak exekutatzeko zerbitzari fisiko kopuru handi batetik ingurune koherente bakarra eraikitzeko gaitasuna izan zuten. eskuzko baliabideen kudeaketaren beharrik gabe.

Docker

Docker aplikazioen edukiontzien software ospetsuena da. Go hizkuntzan idatzita, Linux kernelaren ezaugarri estandarrak erabiltzen ditu - cgroups, namespaces, gaitasunak, etab., baita Aufs fitxategi sistemak eta horrelakoak diskoko lekua aurrezteko.

Docker eta guzti, guztiak, guztiak
Iturria: wikimedia

arkitektura

1.11 bertsioaren aurretik, Docker-ek edukiontziekin eragiketa guztiak egiten zituen zerbitzu bakar gisa funtzionatzen zuen: edukiontzietarako irudiak deskargatu, edukiontziak abiarazi, API eskaerak prozesatu. 1.11 bertsiotik hasita, Docker elkarren artean elkarreragiten duten hainbat zatitan banatu zen: containerd, edukiontzien bizi-ziklo osoa prozesatzeko (diskoko espazioa esleitzea, irudiak deskargatzea, sarearekin lan egitea, edukiontzien egoera abiarazi, instalatzea eta kontrolatzea) eta runC, edukiontzien exekuzio ingurunea, cgroups eta Linux kernelaren beste ezaugarri batzuen erabileran oinarrituta. Docker zerbitzuak berak jarraitzen du, baina orain containerd-era itzulitako API eskaerak prozesatzeko baino ez du balio.

Docker eta guzti, guztiak, guztiak

Instalazioa eta konfigurazioa

Docker instalatzeko gehien gustatzen zaidan modua docker-machine da, zeinak, urruneko zerbitzarietan docker zuzenean instalatzea eta konfiguratzeaz gain (hainbat hodei barne), urruneko zerbitzarietako fitxategi-sistemekin lan egiteko aukera ematen du eta hainbat komando ere exekutatu ditzake.

Hala ere, 2018az geroztik, proiektua ez da ia garatu, beraz, Linux banaketa gehienetarako modu estandarrean instalatuko dugu - biltegi bat gehituz eta beharrezko paketeak instalatuz.

Metodo hau instalazio automatizaturako ere erabiltzen da, adibidez Ansible edo antzeko beste sistema batzuk erabiliz, baina ez dut artikulu honetan kontuan hartuko.

Instalazioa Centos 7-n egingo da, makina birtual bat erabiliko dut zerbitzari gisa, instalatzeko, exekutatu beheko komandoak:

# 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

Instalatu ondoren, zerbitzua hasi eta abian jarri behar duzu:

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

Gainera, docker talde bat sor dezakezu, zeinen erabiltzaileek dockerrekin sudorik gabe lan egin ahal izango dute, erregistroa konfiguratu, kanpotik APIrako sarbidea gaitu eta ez ahaztu suebakia zehatzago konfiguratzea (onartzen ez den guztia). goiko eta beheko adibideetan debekatuta dago - sinpletasun eta argitasunerako utzi dut hau), baina ez dut hemen xehetasun gehiagorik sartuko.

Beste ezaugarri batzuk

Aipatutako docker makinaz gain, docker erregistroa ere badago, edukiontzietarako irudiak gordetzeko tresna, baita docker compose ere, aplikazioak edukiontzietan hedatzea automatizatzeko tresna, YAML fitxategiak edukiontziak eraiki eta konfiguratzeko erabiltzen dira. eta erlazionatutako beste gauza batzuk (adibidez, sareak, datuak biltegiratzeko fitxategi sistema iraunkorrak).

CICDrako zinta garraiatzaileak antolatzeko ere erabil daiteke. Beste ezaugarri interesgarri bat kluster moduan lan egitea da, swarm modua deritzona (1.12 bertsioaren aurretik docker swarm izenez ezagutzen zen), eta horrek edukiontziak exekutatzeko hainbat zerbitzarietatik azpiegitura bakarra muntatzeko aukera ematen du. Zerbitzari guztien gainean sare birtual baterako laguntza dago, karga-orekatzailea integratuta dago, baita edukiontzientzako sekretuen laguntza ere.

Docker compose-ko YAML fitxategiak, aldaketa txikiekin, horrelako klusterretarako erabil daitezke, kluster txiki eta ertainen mantentze-lanak erabat automatizatuz hainbat helburutarako. Kluster handietarako, Kubernetes hobe da swarm moduaren mantentze-kostuak Kubernetesenak gainditu ditzakeelako. RunC gain, adibidez, edukiontzien exekuzio ingurune gisa instala dezakezu Kata ontziak

Docker-ekin lan egiten

Instalatu eta konfiguratu ondoren, garapen-taldearentzat GitLab eta Docker Registry zabalduko ditugun kluster bat muntatzen saiatuko gara. Hiru makina birtual zerbitzari gisa erabiliko ditut, eta horietan banatutako FS GlusterFS ere zabalduko dut; Docker bolumen biltegiratze gisa erabiliko dut, adibidez, docker erregistroaren akats-tolerantea exekutatzeko. Exekutatu beharreko funtsezko osagaiak: Docker Registry, Postgresql, Redis, GitLab Swarm-en gainean GitLab Runner-erako laguntzarekin. Postgresql clustering-arekin abiaraziko dugu Estoloia, beraz, ez duzu GlusterFS erabili behar Postgresql datuak gordetzeko. Gainerako datu kritikoak GlusterFS-en gordeko dira.

GlusterFS zerbitzari guztietan zabaltzeko (node1, node2, node3 deitzen zaie), paketeak instalatu, suebakia gaitu eta beharrezko direktorioak sortu behar dituzu:

# 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

Instalatu ondoren, GlusterFS konfiguratzeko lanak nodo batetik jarraitu behar dira, adibidez, 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

Ondoren, ondoriozko bolumena muntatu behar duzu (komandoa zerbitzari guztietan exekutatu behar da):

# mount /srv/docker

Swarm modua zerbitzarietako batean konfiguratuta dago, liderra izango dena, gainerakoak klusterra sartu beharko dira, beraz, komandoa lehen zerbitzarian exekutatzeko emaitza besteetan kopiatu eta exekutatu beharko da.

Hasierako kluster konfigurazioa, komandoa exekutatzen dut node1-en:

# 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

Bigarren komandoaren emaitza kopiatzen dugu eta node2 eta node3-n exekutatzen dugu:

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

Une honetan, zerbitzarien aurretiazko konfigurazioa amaitu da, ekin gaitezen zerbitzuak konfiguratzen; exekutatu beharreko komandoak nodo1etik abiaraziko dira, kontrakoa zehaztu ezean.

Lehenik eta behin, sor ditzagun edukiontzientzako sareak:

# 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

Gero zerbitzariak markatzen ditugu, hau beharrezkoa da zerbitzu batzuk zerbitzariekin lotzeko:

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

Ondoren, etcd datuak gordetzeko direktorioak sortzen ditugu, KV biltegiratzea, Traefik eta Stolon-entzat beharrezkoak direnak. Postgresql-en antzera, hauek zerbitzariei lotuta dauden edukiontziak izango dira, beraz, komando hau zerbitzari guztietan exekutatzen dugu:

# mkdir -p /srv/etcd

Ondoren, sortu fitxategi bat etcd konfiguratzeko eta erabili:

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

Denbora pixka bat igaro ondoren, etcd cluster-a martxan dagoela egiaztatuko dugu:

# 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

Postgresql-erako direktorioak sortzen ditugu, komandoa zerbitzari guztietan exekutatzen dugu:

# mkdir -p /srv/pgsql

Ondoren, sortu fitxategi bat Postgresql konfiguratzeko:

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

Sekretuak sortzen ditugu eta fitxategia erabiltzen dugu:

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

Denbora pixka bat igaro ondoren (ikus komandoaren irteera docker zerbitzua lszerbitzu guztiak martxan daudela) Postgresql klusterra hasieratzen dugu:

# 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 klusterren prest dagoen egiaztatzea:

# 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

Traefik konfiguratzen dugu edukiontzietarako sarbidea irekitzeko kanpotik:

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

Redis Cluster abiarazten dugu, horretarako biltegiratze direktorio bat sortzen dugu nodo guztietan:

# 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

Gehitu Docker Erregistroa:

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

Eta azkenik - 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

Klusterren eta zerbitzuen azken egoera:

# 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

Zer gehiago hobetu daiteke? Ziurtatu Traefik konfiguratzen duzula edukiontziak https-ren bidez exekutatzeko, gehitu tls enkriptatzea Postgresql eta Redis-entzat. Baina, oro har, dagoeneko garatzaileei eman diezaieke PoC gisa. Ikus ditzagun orain Dockerren alternatibak.

podman

Beste motor nahiko ezagun bat lekaren arabera multzokatutako edukiontziak martxan jartzeko (podak, elkarrekin zabaldutako edukiontzi taldeak). Docker-ek ez bezala, ez du inolako zerbitzurik behar edukiontziak exekutatzeko; lan guztiak libpod liburutegiaren bidez egiten dira. Go-n ere idatzita, OCI-rekin bateragarria den exekuzio-denbora behar da edukiontziak exekutatzeko, runC adibidez.

Docker eta guzti, guztiak, guztiak

Podman-ekin lan egiteak, oro har, hori gogorarazten du Dockerrentzat, horrela egin dezakezun punturaino (probatu duten askok, artikulu honen egilea barne):

$ alias docker=podman

eta lanean jarraitu dezakezu. Oro har, Podman-en egoera oso interesgarria da, izan ere, Kubernetes-en lehen bertsioek Dockerrekin funtzionatzen bazuten, 2015 inguruan, edukiontzien mundua estandarizatu ondoren (OCI - Open Container Initiative) eta Docker-en containerd eta runC-tan banatu ondoren, Kubernetesen exekutatzeko Dockerren alternatiba bat garatzen ari da: CRI-O. Zentzu honetan Podman Dockerren alternatiba da, Kubernetesen printzipioetan eraikia, edukiontziak taldekatzea barne, baina proiektuaren helburu nagusia Docker estiloko edukiontziak zerbitzu gehigarririk gabe abian jartzea da. Arrazoi bistakoengatik, ez dago swarm modurik, garatzaileek argi esaten baitute kluster bat behar baduzu, hartu Kubernetes.

Instalazio-

Centos 7-n instalatzeko, aktibatu Extras biltegia eta, ondoren, dena instalatu komandoarekin:

# yum -y install podman

Beste ezaugarri batzuk

Podman-ek sistemarako unitateak sor ditzake, horrela zerbitzaria berrabiarazi ondoren edukiontziak abiarazteko arazoa konpontzeko. Gainera, systemd ontzian pid 1 bezala funtzionatzen duela deklaratu da. Ontziak eraikitzeko buildah tresna bereizi bat dago, hirugarrenen tresnak ere badaude - docker-compose-ren analogoak, Kubernetesekin bateragarriak diren konfigurazio-fitxategiak ere sortzen dituztenak, beraz, Podman-etik Kubernetes-erako trantsizioa ahalik eta gehien errazten da.

Podman-ekin lan egiten

Swarm modurik ez dagoenez (kluster bat behar izanez gero Kubernetesera aldatu behar dugu), edukiontzi bereizietan bilduko dugu.

Instalatu podman-compose:

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

Ondorioz, podman-en konfigurazio-fitxategia zertxobait desberdina da, beraz, adibidez, bolumenen atal bereizi bat zuzenean zerbitzuen atalera eraman behar izan dugu.

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

Emaitza:

# 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

Ikus dezagun zer sortzen duen systemd eta kubernetesentzat, horretarako pod-aren izena edo id-a aurkitu behar dugu:

# 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

Zoritxarrez, edukiontziak abiarazteaz gain, systemd-erako sortutako unitateak ez du beste ezer egiten (adibidez, edukiontzi zaharrak garbitzen ditu zerbitzu bat berrabiarazten denean), beraz, zuk zeuk idatzi beharko dituzu horrelakoak.

Printzipioz, Podman nahikoa da edukiontziak zer diren probatzeko, docker-compose-rako konfigurazio zaharrak transferitzeko eta, gero, Kubernetesera joateko, kluster bat behar baduzu, edo Dockerren alternatiba errazagoa lortzeko.

rkt

Proiektu artxiboetan sartu zen Duela sei hilabete inguru RedHatek erosi zuelako, beraz, ez naiz zehatzago azalduko. Orokorrean, oso inpresio ona utzi zuen, baina Dockerrekin eta bereziki Podmanekin alderatuta, konbinazio bat dirudi. rkt-en gainean eraikitako CoreOS banaketa ere bazegoen (jatorrian Docker zuten arren), baina RedHat erosi ondoren ere laguntzarekin amaitu zen.

Peluxa

Gehiago proiektu bat, horren egileak edukiontziak eraiki eta exekutatu nahi zituen. Dokumentazioa eta kodea ikusita, egileak ez zituen estandarrak jarraitu, baizik eta bere inplementazioa idaztea erabaki zuen, eta hori, printzipioz, egin zuen.

Findings

Kubernetes-en egoera oso interesgarria da: alde batetik, Docker-ekin kluster bat eraiki dezakezu (swirm moduan), eta horrekin bezeroentzako produktu-inguruneak ere exekutatu ditzakezu, hau bereziki egia da talde txikientzat (3-5 pertsona). , edo karga orokor txiki batekin, edo Kubernetes konfiguratzeko zailtasunak ulertzeko gogorik eza, karga handietarako barne.

Podman-ek ez du bateragarritasun osoa eskaintzen, baina abantaila garrantzitsu bat du: Kubernetesekin bateragarritasuna, tresna osagarriak barne (buildah eta beste). Hori dela eta, honela planteatuko dut lanerako tresna bat aukeratzera: talde txikietarako edo aurrekontu mugatu batekin - Docker (swirm modu posible batekin), neure burua lokaleko ostalari pertsonal batean garatzeko - Podman adiskideak eta beste guztientzat. - Kubernetes.

Ez nago ziur Dockerren egoera etorkizunean aldatuko ez denik, azken finean, aitzindariak dira, eta, gainera, pixkanaka-pixkanaka estandarizatzen ari dira, baina Podmanek, dituen gabezi guztiengatik (Linux-en bakarrik funtzionatzen du, clustering gabe, muntaia eta beste ekintza batzuk hirugarrenen irtenbideak dira) etorkizuna argiagoa da, beraz, guztioi gonbidatzen dut aurkikuntza hauek iruzkinetan eztabaidatzera.

PS Abuztuaren 3an "Docker bideo ikastaroa", non bere lanari buruz gehiago jakin dezakezun. Bere tresna guztiak aztertuko ditugu: oinarrizko abstrakzioetatik sareko parametroetaraino, hainbat sistema eragilerekin eta programazio lengoaiarekin lan egiteko ñabardurak. Teknologia ezagutuko duzu eta Docker non eta nola erabili onena ulertuko duzu. Praktika onen kasuak ere partekatuko ditugu.

Erreserbaren prezioa kaleratu aurretik: 5000 RUB. Docker Bideo Ikastaroaren programa ikus dezakezu ikastaroaren orrian.

Iturria: www.habr.com

Gehitu iruzkin berria