Docker kaj ĉio, ĉio, ĉio

TL;DR: Superrigarda artikolo - gvidilo por kompari mediojn por ruli aplikaĵojn en ujoj. La eblecoj de Docker kaj aliaj similaj sistemoj estos konsiderataj.

Docker kaj ĉio, ĉio, ĉio

Eta historio de kie ĉio venis

История

La unua konata maniero izoli aplikaĵon estas chroot. La samnoma sistemvoko disponigas ŝanĝon al la radika dosierujo - tiel havigante aliron al la programo kiu vokis ĝin, aliron nur al dosieroj ene de ĉi tiu dosierujo. Sed se la programo ricevas superuzantrajtojn interne, ĝi eble povas "eskapi" de la chroot kaj akiri aliron al la ĉefa operaciumo. Ankaŭ, krom ŝanĝi la radikan dosierujon, aliaj rimedoj (RAM, procesoro), same kiel aliro al la reto, ne estas limigitaj.

La sekva maniero estas lanĉi plenan operaciumon ene de la ujo, uzante la mekanismojn de la operaciumo-kerno. Ĉi tiu metodo nomiĝas malsame en malsamaj operaciumoj, sed la esenco estas la sama - kurante plurajn sendependajn operaciumojn, ĉiu el kiuj funkcias per la sama kerno, kiu funkcias la ĉefan operaciumon. Ĉi tio inkluzivas FreeBSD Jails, Solaris Zones, OpenVZ kaj LXC por Linukso. Izolaĵo estas provizita ne nur por diskospaco, sed ankaŭ por aliaj rimedoj, precipe ĉiu ujo povas havi limigojn pri procesora tempo, RAM, reta bendolarĝo. Kompare kun chroot, lasi la ujo estas pli malfacila, ĉar la superuzanto en la ujo havas aliron nur al la interno de la ujo, tamen pro la bezono teni la operaciumon ene de la ujo ĝisdatigita kaj la uzo de malnova kerno. versioj (gravaj por Linukso, en pli malgranda mezuro FreeBSD), estas ne-nula la probableco trarompi la kernan izoligan sistemon kaj akiri aliron al la ĉefa operaciumo.

Anstataŭ lanĉi plenan operaciumon en ujo (kun komenca sistemo, pakaĵadministranto ktp.), aplikaĵoj povas esti lanĉitaj tuj, la ĉefa afero estas provizi aplikojn kun ĉi tiu ŝanco (la ĉeesto de la necesaj bibliotekoj kaj aliaj dosieroj). Ĉi tiu ideo servis kiel bazo por kontenerigita aplikaĵvirtualigo, kies plej elstara kaj konata reprezentanto estas Docker. Kompare kun antaŭaj sistemoj, pli flekseblaj izolaj mekanismoj, kune kun enkonstruita subteno por virtualaj retoj inter ujoj kaj aplikaĵa stato ene de ujo, rezultigis la kapablon konstrui ununuran holistikan medion de granda nombro da fizikaj serviloj por ruli ujojn - sen la bezono de mana rimedadministrado.

Docker

Docker estas la plej konata aplikaĵa konteneriga programaro. Skribita en la Go-lingvo, ĝi uzas la regulajn kapablojn de la Linukso-kerno - cgroups, nomspacoj, kapabloj, ktp., same kiel Aufs-dosiersistemojn kaj aliajn similajn por ŝpari diskospacon.

Docker kaj ĉio, ĉio, ĉio
Fonto: vikimedio

arkitekturo

Antaŭ versio 1.11, Docker funkciis kiel ununura servo, kiu plenumis ĉiujn operaciojn kun ujoj: elŝuti bildojn por ujoj, lanĉi ujojn, prilabori API-petojn. Ekde versio 1.11, Docker estis dividita en plurajn partojn, kiuj interagas unu kun la alia: containerd, por pritrakti la tutan vivociklon de ujoj (asigno de diskospaco, elŝutado de bildoj, interkonektado, lanĉo, instalo kaj monitorado de la stato de ujoj) kaj runC. , konteneraj rultempoj, surbaze de la uzo de cgroups kaj aliaj funkcioj de la Linukso-kerno. La docker-servo mem restas, sed nun ĝi nur servas por prilabori API-petojn elsenditajn al containerd.

Docker kaj ĉio, ĉio, ĉio

Instalado kaj agordo

Mia plej ŝatata maniero instali docker estas docker-machine, kiu, krom rekte instali kaj agordi docker sur foraj serviloj (inkluzive de diversaj nuboj), permesas vin labori kun la dosiersistemoj de foraj serviloj, kaj ankaŭ povas ruli diversajn komandojn.

Tamen, ekde 2018, la projekto apenaŭ disvolviĝis, do ni instalos ĝin laŭ la kutima maniero por la plej multaj Linuksaj distribuoj - aldonante deponejon kaj instalante la necesajn pakaĵojn.

Ĉi tiu metodo ankaŭ estas uzata por aŭtomata instalado, ekzemple, uzante Ansible aŭ aliajn similajn sistemojn, sed mi ne konsideros ĝin en ĉi tiu artikolo.

Instalado estos farita sur Centos 7, mi uzos virtualan maŝinon kiel servilon, por instali, nur rulu la subajn komandojn:

# 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

Post instalado, vi devas komenci la servon, meti ĝin en aŭtomatan ŝarĝon:

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

Aldone, vi povas krei docker-grupon, kies uzantoj povos labori kun docker sen sudo, agordi ensalutadon, ebligi aliron al la API de ekstere, ne forgesu agordi la fajroŝirmilon (ĉio, kio ne estas permesita, estas malpermesite en la supraj kaj malsupraj ekzemploj - mi preterlasis tion por simpleco kaj bildigo), sed mi ne eniros pli detale ĉi tie.

Aliaj trajtoj

Krom ĉi-supra docker-maŝino, ekzistas ankaŭ docker-registro, ilo por stoki bildojn por ujoj, kaj ankaŭ docker-komponadon - ilo por aŭtomatigi la disfaldiĝon de aplikoj en ujoj, YAML-dosieroj estas uzataj por konstrui kaj agordi ujojn kaj aliaj rilataj aferoj (ekzemple, retoj, persistaj dosiersistemoj por konservi datumojn).

Ĝi ankaŭ povas esti uzata por organizi duktojn por CICD. Alia interesa trajto funkcias en cluster-reĝimo, la tielnomita svarma reĝimo (antaŭ versio 1.12 ĝi estis konata kiel docker-svarmo), kiu ebligas al vi kunmeti ununuran infrastrukturon de pluraj serviloj por ruli ujojn. Estas subteno por virtuala reto aldone al ĉiuj serviloj, ekzistas enkonstruita ŝarĝbalancilo, kaj ankaŭ subteno por sekretoj por ujoj.

La YAML-dosieroj de docker compose povas esti uzataj por tiaj aretoj kun malgrandaj modifoj, plene aŭtomatigante la prizorgadon de malgrandaj kaj mezaj aretoj por diversaj celoj. Por grandaj aretoj, Kubernetes estas preferinda ĉar la kostoj pri bontenado de svarmanoj povas superi tiujn de Kubernetes. Krom runC, kiel ekzekutmedio por ujoj, vi povas instali, ekzemple Kata ujoj

Laborante kun Docker

Post instalado kaj agordo, ni provos konstrui areton en kiu ni disfaldiĝos GitLab kaj Docker Registry por la evolua teamo. Kiel serviloj, mi uzos tri virtualajn maŝinojn, sur kiuj mi aldone deplojos la distribuitan FS de GlusterFS, mi uzos ĝin kiel stokado de docker-volumoj, ekzemple, por ruli sekuran version de la docker-registro. Ŝlosilaj komponantoj por ruli: Docker Registry, Postgresql, Redis, GitLab kun subteno por GitLab Runner supre de Swarm. Postgresql estos lanĉita kun clustering Stolon, do vi ne bezonas uzi GlusterFS por stoki Postgresql-datumojn. La resto de la kritikaj datumoj estos konservitaj en GlusterFS.

Por deploji GlusterFS sur ĉiuj serviloj (ili nomiĝas nodo1, nodo2, nodo3), vi devas instali pakaĵojn, ebligi la fajroŝirmilon, krei la necesajn dosierujojn:

# 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

Post instalado, laboro pri agordo de GlusterFS devas esti daŭrigita de unu nodo, ekzemple nodo1:

# 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

Tiam vi devas munti la rezultan volumon (la komando devas esti rulita sur ĉiuj serviloj):

# mount /srv/docker

Svarma reĝimo estas agordita sur unu el la serviloj, kiu estos Ĉefo, la resto devos aliĝi al la areto, do la rezulto de rulado de la komando sur la unua servilo devos esti kopiita kaj ekzekutita sur la resto.

Komenca agordo de grapolo, mi rulas la komandon sur nodo1:

# 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

Kopiu la rezulton de la dua komando, ekzekutu sur nodo2 kaj nodo3:

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

Ĉi tio kompletigas la antaŭan agordon de la serviloj, ni komencu agordi la servojn, la ekzekutotaj komandoj estos lanĉitaj de nodo1, krom se alie specifita.

Antaŭ ĉio, ni kreu retojn por ujoj:

# 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

Tiam ni markas la servilojn, ĉi tio estas necesa por ligi iujn servojn al la serviloj:

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

Poste ni kreas dosierujojn por stoki etcd-datumojn, la KV-stokadon, kiun bezonas Traefik kaj Stolon. Simile al Postgresql, ĉi tiuj estos ujoj ligitaj al serviloj, do ni plenumas ĉi tiun komandon en ĉiuj serviloj:

# mkdir -p /srv/etcd

Poste, kreu dosieron por agordi etcd kaj apliki ĝin:

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

Post iom da tempo, ni kontrolas, ke la etcd-areto altiĝis:

# 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

Kreu dosierujojn por Postgresql, faru la komandon en ĉiuj serviloj:

# mkdir -p /srv/pgsql

Poste, kreu dosieron por agordi 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

Ni generas sekretojn, aplikas la dosieron:

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

Iom da tempo poste (rigardu la eligon de la komando docker servo lske ĉiuj servoj altiĝis) pravalorigu la Postgresql-grupon:

# 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

Kontrolante la pretecon de la Postgresql-grupo:

# 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

Ni agordas traefik por malfermi aliron al ujoj de ekstere:

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

Ni komencas Redis Cluster, por tio ni kreas stokan dosierujon sur ĉiuj nodoj:

# 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

Aldonu Docker-Registron:

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

Kaj finfine - 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

La fina stato de la areto kaj servoj:

# 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

Kion alian oni povas plibonigi? Nepre agordu Traefik por labori kun https-ujoj, aldonu tls-ĉifradon por Postgresql kaj Redis. Sed ĝenerale, vi jam povas doni ĝin al programistoj kiel PoC. Ni nun rigardu alternativojn al Docker.

podman

Alia sufiĉe konata motoro por prizorgi ujojn grupigitajn laŭ balgoj (pods, grupoj da ujoj deplojitaj kune). Male al Docker, ĝi ne postulas ajnan servon por ruli ujojn, ĉiu laboro estas farita per la libpod-biblioteko. Ankaŭ skribita en Go, bezonas OCI-konforman rultempon por ruli ujojn kiel runC.

Docker kaj ĉio, ĉio, ĉio

Labori kun Podman ĝenerale similas al tiu de Docker, tiom kiom vi povas fari ĝin tiel (postulita de multaj, kiuj provis ĝin, inkluzive de la aŭtoro de ĉi tiu artikolo):

$ alias docker=podman

kaj vi povas plu labori. Ĝenerale, la situacio kun Podman estas tre interesa, ĉar se la fruaj versioj de Kubernetes funkciis kun Docker, tiam ekde proksimume 2015, post normigado de la kontenera mondo (OCI - Open Container Initiative) kaj dividi Docker en containerd kaj runC, alternativo al Docker estas disvolvita por funkcii en Kubernetes: CRI-O. Podman ĉi-rilate estas alternativo al Docker, konstruita sur la principoj de Kubernetes, inkluzive de kontenera grupigo, sed la ĉefa celo de la projekto estas ruli Docker-stilaj ujoj sen aldonaj servoj. Pro evidentaj kialoj, ne ekzistas svarma reĝimo, ĉar la programistoj klare diras, ke se vi bezonas areton, prenu Kubernetes.

fikso

Por instali sur Centos 7, simple aktivigu la deponejon de Kromaĵoj, kaj poste instalu ĉion per la komando:

# yum -y install podman

Aliaj trajtoj

Podman povas generi unuojn por systemd, tiel solvante la problemon de lanĉado de ujoj post servila rekomenco. Aldone, systemd estas deklarita funkcii ĝuste kiel pid 1 en la ujo. Por konstrui ujojn, ekzistas aparta buildah-ilo, ekzistas ankaŭ triaj iloj - analogoj de docker-compose, kiu ankaŭ generas Kubernetes-kongruajn agordajn dosierojn, do la transiro de Podman al Kubernetes estas kiel eble plej simpla.

Laborante kun Podman

Ĉar ne ekzistas svarma reĝimo (ĝi devas ŝanĝi al Kubernetes se bezonata areto), ni kunvenos ĝin en apartaj ujoj.

Instalu podman-compose:

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

La rezulta agordosiero por podman estas iomete malsama, ĉar ekzemple ni devis movi apartan sekcion de volumoj rekte al la sekcio de servoj.

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

Rezulto de laboro:

# 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

Ni vidu, kion ĝi generos por systemd kaj kubernetes, por tio ni devas eltrovi la nomon aŭ identigilon de la pod:

# 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

Bedaŭrinde, krom ruli ujojn, la generita unuo por systemd faras nenion alian (ekzemple, purigi malnovajn ujojn kiam tia servo estas rekomencita), do vi devos aldoni tiajn aferojn mem.

En principo, Podman sufiĉas por provi kio estas ujoj, translokigi malnovajn agordojn por docker-compose, kaj tiam iri al Kubernetes, se necese, sur areto, aŭ akiri pli facile uzeblan alternativon al Docker.

rkt

La projekto iris al arkivo antaŭ ĉirkaŭ ses monatoj pro tio, ke RedHat aĉetis ĝin, do mi ne pli detale detale pri ĝi. Ĝenerale ĝi lasis tre bonan impreson, sed kompare kun Docker, kaj eĉ pli kun Podman, ĝi aspektas kiel kombinaĵo. Estis ankaŭ CoreOS-distribuo konstruita sur rkt (kvankam ili origine havis Docker), sed tio ankaŭ finiĝis post la aĉeto de RedHat.

Ekbrilo

Pli unu projekto, kies aŭtoro nur volis konstrui kaj funkciigi ujojn. Juĝante laŭ la dokumentado kaj kodo, la aŭtoro ne sekvis la normojn, sed simple decidis skribi sian propran efektivigon, kion, principe, li faris.

trovoj

La situacio kun Kubernetes estas tre interesa: unuflanke, kun Docker, vi povas kunveni grapolon (en svarma reĝimo), per kiu vi eĉ povas funkciigi produktadmediojn por klientoj, ĉi tio validas precipe por malgrandaj teamoj (3-5 homoj). ), aŭ kun malgranda ĝenerala ŝarĝo , aŭ la manko de deziro kompreni la komplikaĵojn de agordo de Kubernetes, inkluzive por altaj ŝarĝoj.

Podman ne provizas plenan kongruon, sed ĝi havas unu gravan avantaĝon - kongruon kun Kubernetes, inkluzive de pliaj iloj (buildah kaj aliaj). Tial mi traktos la elekton de ilo por laboro jene: por malgrandaj teamoj, aŭ kun limigita buĝeto - Docker (kun ebla svarma reĝimo), por disvolvi por mi mem sur persona loka gastiganto - Podman-kamaradoj, kaj por ĉiuj aliaj. - Kubernetes.

Mi ne certas, ke la situacio kun Docker ne ŝanĝiĝos estonte, ja ili estas pioniroj, kaj ankaŭ malrapide normigas paŝon post paŝo, sed Podman, kun ĉiuj ĝiaj mankoj (funkcias nur en Linukso, sen clustering, asembleo). kaj aliaj agoj estas triaj decidoj) la estonteco estas pli klara, do mi invitas ĉiujn diskuti ĉi tiujn rezultojn en la komentoj.

PS La 3-an de aŭgusto ni lanĉas "Videokurso de Dockerkie vi povas lerni pli pri lia laboro. Ni analizos ĉiujn ĝiajn ilojn: de bazaj abstraktaĵoj ĝis retaj parametroj, nuancoj de laboro kun diversaj operaciumoj kaj programlingvoj. Vi konatiĝos kun la teknologio kaj komprenos kie kaj kiel plej bone uzi Docker. Ni ankaŭ dividos plej bonajn praktikajn kazojn.

Antaŭmendo kosto antaŭ liberigo: 5000 rubloj. La programo "Docker Video Kurso" troviĝas sur la kurspaĝo.

fonto: www.habr.com

Aldoni komenton