Докер және барлығы, барлығы, барлығы

TL;DR: шолу мақаласы – контейнерлердегі қолданбаларды іске қосу үшін орталарды салыстыруға арналған нұсқаулық. Docker және басқа ұқсас жүйелердің мүмкіндіктері қарастырылады.

Докер және барлығы, барлығы, барлығы

Мұның бәрі қайдан шыққаны туралы шағын тарих

История

Қолданбаны оқшаулаудың бірінші белгілі тәсілі - chroot. Бір аттас жүйелік шақыру түбірлік каталогты өзгертуді қамтамасыз етеді - осылайша оны шақырған бағдарламаға қол жеткізуді қамтамасыз етеді, тек осы каталогтың ішіндегі файлдарға қол жеткізу. Бірақ егер бағдарлама ішінде суперпайдаланушы құқығы берілсе, ол chroot-тан «қашып» және негізгі операциялық жүйеге қол жеткізе алады. Сондай-ақ, түбірлік каталогты өзгертуден басқа, басқа ресурстар (RAM, процессор), сондай-ақ желіге кіру шектелмейді.

Келесі жол – операциялық жүйе ядросының механизмдерін пайдалана отырып, контейнер ішінде толыққанды операциялық жүйені іске қосу. Бұл әдіс әртүрлі операциялық жүйелерде әртүрлі деп аталады, бірақ мәні бір - әрқайсысы негізгі операциялық жүйені басқаратын бір ядрода жұмыс істейтін бірнеше тәуелсіз операциялық жүйелерді іске қосу. Бұған Linux үшін FreeBSD Jails, Solaris Zones, OpenVZ және LXC кіреді. Оқшаулау тек дискілік кеңістік үшін ғана емес, сонымен қатар басқа ресурстар үшін де қарастырылған, атап айтқанда, әрбір контейнерде процессор уақытына, жедел жадқа, желі өткізу қабілетіне шектеулер болуы мүмкін. Chroot-пен салыстырғанда, контейнерден шығу қиынырақ, өйткені контейнердегі суперпайдаланушы тек контейнердің ішкі жағына қол жеткізе алады, алайда контейнер ішіндегі операциялық жүйені жаңарту қажеттілігіне және ескі ядро ​​​​пайдалануына байланысты. нұсқаларында (Linux үшін, аз дәрежеде FreeBSD) ядроны оқшаулау жүйесін «жарып өту» және негізгі операциялық жүйеге қол жеткізу ықтималдығы нөлге тең емес.

Контейнерде толыққанды операциялық жүйені іске қосудың орнына (инициализация жүйесімен, пакет менеджері және т. басқа файлдар). Бұл идея контейнерлік қолданбаларды виртуалдандыру үшін негіз болды, оның ең көрнекті және танымал өкілі Docker болып табылады. Алдыңғы жүйелермен салыстырғанда, икемді оқшаулау механизмдері, контейнерлер арасындағы виртуалды желілерді және контейнер ішіндегі қолданба күйін қолдаумен бірге, көптеген физикалық серверлерден контейнерлерді іске қосу үшін біртұтас ортаны құру мүмкіндігіне әкелді. ресурстарды қолмен басқару қажеттілігі.

Докер

Docker - қолданбаларды контейнерлеудің ең танымал бағдарламалық құралы. Go тілінде жазылған ол Linux ядросының тұрақты мүмкіндіктерін – топтарды, аттар кеңістігін, мүмкіндіктерді және т.б., сондай-ақ Aufs файлдық жүйелерін және дискілік кеңістікті үнемдеу үшін ұқсас басқаларды пайдаланады.

Докер және барлығы, барлығы, барлығы
Дереккөз: wikimedia

сәулет

1.11 нұсқасына дейін Docker контейнерлермен барлық операцияларды орындайтын бір қызмет ретінде жұмыс істеді: контейнерлерге суреттерді жүктеп алу, контейнерлерді іске қосу, API сұрауларын өңдеу. 1.11 нұсқасынан бастап Docker бір-бірімен өзара әрекеттесетін бірнеше бөліктерге бөлінді: контейнерлер, контейнерлердің бүкіл өмірлік циклін өңдеу үшін (дискілік кеңістікті бөлу, кескіндерді жүктеу, желіні құру, іске қосу, орнату және контейнерлердің күйін бақылау) және runC , топтарды және Linux ядросының басқа мүмкіндіктерін пайдалануға негізделген контейнердің орындалу уақыты. Докер қызметінің өзі қалады, бірақ қазір ол тек контейнерге таратылатын API сұрауларын өңдеуге қызмет етеді.

Докер және барлығы, барлығы, барлығы

Орнату және конфигурация

Доккерді орнатудың менің сүйікті тәсілі - қашықтағы серверлерде (соның ішінде әртүрлі бұлттарда) докерді тікелей орнату және конфигурациялаумен қатар, қашықтағы серверлердің файлдық жүйелерімен жұмыс істеуге мүмкіндік беретін, сонымен қатар әртүрлі пәрмендерді іске қоса алатын докер-машинасы.

Дегенмен, 2018 жылдан бастап жоба әрең әзірленді, сондықтан біз оны Linux дистрибутивтерінің көпшілігі үшін әдеттегі жолмен орнатамыз - репозиторийді қосу және қажетті пакеттерді орнату.

Бұл әдіс автоматтандырылған орнату үшін де қолданылады, мысалы, Ansible немесе басқа ұқсас жүйелерді пайдалану, бірақ мен оны осы мақалада қарастырмаймын.

Орнату Centos 7 жүйесінде жүзеге асырылады, мен виртуалды машинаны сервер ретінде қолданамын, орнату үшін төмендегі пәрмендерді орындаңыз:

# 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

Орнатқаннан кейін қызметті іске қосу керек, оны автожүктемеге қойыңыз:

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

Сонымен қатар, сіз докер тобын жасай аласыз, оның пайдаланушылары sudoсыз докермен жұмыс істей алады, журналды баптай алады, API-ге сырттан қол жеткізуді қоса алады, брандмауэрді дәл баптауды ұмытпаңыз (рұқсат етілмеген барлық нәрсе жоғарыдағы және төменде келтірілген мысалдарда тыйым салынған - мен мұны қарапайымдылық пен визуализация үшін өткізіп жібердім), бірақ мен мұнда толығырақ тоқталмаймын.

Басқа мүмкіндіктер

Жоғарыда аталған докерлік машинадан басқа, докер тізілімі, контейнерлерге арналған кескіндерді сақтауға арналған құрал, сонымен қатар докер құрастыру - контейнерлерде қолданбаларды орналастыруды автоматтандыру құралы, YAML файлдары контейнерлерді құру және конфигурациялау үшін қолданылады және басқа байланысты нәрселер (мысалы, желілер, деректерді сақтауға арналған тұрақты файлдық жүйелер).

Оны CICD үшін құбырларды ұйымдастыру үшін де пайдалануға болады. Тағы бір қызықты мүмкіндік - кластерлік режимде жұмыс істейді, бұл контейнерлерді іске қосу үшін бірнеше серверлерден бір инфрақұрылымды жинауға мүмкіндік беретін үйір режимі (1.12 нұсқасына дейін ол докер тобы ретінде белгілі болды). Барлық серверлердің үстінде виртуалды желіге қолдау бар, кірістірілген жүктеме балансы бар, сонымен қатар контейнерлерге арналған құпияларды қолдау бар.

Docker compose YAML файлдарын әртүрлі мақсаттар үшін шағын және орта кластерлерге техникалық қызмет көрсетуді толығымен автоматтандыратын шағын модификациялары бар осындай кластерлер үшін пайдалануға болады. Үлкен кластерлер үшін Kubernetes жақсырақ, өйткені үйір режиміне қызмет көрсету шығындары Kubernetes-тен асып түсуі мүмкін. Контейнерлер үшін орындау ортасы ретінде runC-ге қосымша, мысалы, орнатуға болады Ката контейнерлері

Docker-пен жұмыс

Орнату мен конфигурациялаудан кейін біз әзірлеу тобы үшін GitLab және Docker тізілімін орналастыратын кластерді құруға тырысамыз. Серверлер ретінде мен үш виртуалды машинаны қолданамын, оларда GlusterFS таратылған FS қосымша орналастырамын, мен оны докер томдарының қоймасы ретінде пайдаланамын, мысалы, докер тізілімінің қатесіз нұсқасын іске қосу үшін. Іске қосылатын негізгі компоненттер: Docker Registry, Postgresql, Redis, GitLab Swarm жоғарғы жағындағы GitLab Runner қолдауымен. Postgresql кластерлеу арқылы іске қосылады Столон, сондықтан Postgresql деректерін сақтау үшін GlusterFS пайдаланудың қажеті жоқ. Қалған маңызды деректер GlusterFS жүйесінде сақталады.

GlusterFS-ті барлық серверлерде орналастыру үшін (олар түйін1, түйін2, түйін3 деп аталады) бумаларды орнату, брандмауэрді қосу, қажетті каталогтарды жасау керек:

# 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

Орнатқаннан кейін GlusterFS конфигурациялау жұмысын бір түйіннен жалғастыру керек, мысалы, 1 түйін:

# 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

Содан кейін алынған көлемді орнату керек (пәрмен барлық серверлерде орындалуы керек):

# mount /srv/docker

Swarm режимі серверлердің бірінде конфигурацияланған, ол Лидер болады, қалғандары кластерге қосылуы керек, сондықтан бірінші серверде пәрменді іске қосу нәтижесі қалғандарында көшіріліп, орындалуы керек.

Бастапқы кластерді орнату, мен 1 node пәрменін іске қосамын:

# 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

Екінші пәрменнің нәтижесін көшіріп, 2 және 3 түйінінде орындаңыз:

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

Бұл серверлердің алдын ала конфигурациясын аяқтайды, қызметтерді конфигурациялауды бастайық, егер басқаша көрсетілмесе, орындалатын пәрмендер 1 түйіннен іске қосылады.

Ең алдымен контейнерлер үшін желілерді құрайық:

# 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

Содан кейін біз серверлерді белгілейміз, бұл кейбір қызметтерді серверлерге байланыстыру үшін қажет:

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

Әрі қарай, Traefik және Stolon қажет KV қоймасы, etcd деректерін сақтауға арналған каталогтарды жасаймыз. Postgresql сияқты, бұл серверлерге байланыстырылған контейнерлер болады, сондықтан біз бұл пәрменді барлық серверлерде орындаймыз:

# mkdir -p /srv/etcd

Содан кейін etcd конфигурациялау үшін файл жасаңыз және оны қолданыңыз:

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

Біраз уақыттан кейін etcd кластерінің көтерілгенін тексереміз:

# 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 үшін каталогтарды жасаңыз, барлық серверлерде пәрменді орындаңыз:

# mkdir -p /srv/pgsql

Содан кейін 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

Біз құпияларды жасаймыз, файлды қолданамыз:

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

Біраз уақыттан кейін (пәрменнің нәтижесін қараңыз докер қызметі lsбарлық қызметтер көтерілді) Postgresql кластерін инициализациялаңыз:

# 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 кластерінің дайындығын тексеру:

# 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 конфигурациясын контейнерлерге сырттан кіруге рұқсат етеміз:

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 кластерін бастаймыз, ол үшін барлық түйіндерде сақтау каталогын жасаймыз:

# 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

Docker тізілімін қосу:

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

Соңында - 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

Кластер мен қызметтердің соңғы жағдайы:

# 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

Тағы нені жақсартуға болады? Traefik бағдарламасын https контейнерлерімен жұмыс істеу үшін конфигурациялауды ұмытпаңыз, Postgresql және Redis үшін tls шифрлауын қосыңыз. Бірақ жалпы алғанда, сіз оны әзірлеушілерге PoC ретінде бере аласыз. Енді Docker баламаларын қарастырайық.

Подман

Тұтқалар бойынша топтастырылған контейнерлерді іске қосуға арналған тағы бір танымал қозғалтқыш (подтар, бірге орналастырылған контейнерлер топтары). Docker-тен айырмашылығы, ол контейнерлерді іске қосу үшін ешқандай қызметті қажет етпейді, барлық жұмыс libpod кітапханасы арқылы орындалады. Сондай-ақ Go бағдарламасында жазылған, runC сияқты контейнерлерді іске қосу үшін OCI үйлесімді жұмыс уақыты қажет.

Докер және барлығы, барлығы, барлығы

Жалпы Подманмен жұмыс істеу Docker жұмысына ұқсайды, сондықтан сіз мұны осылай жасай аласыз (оны қолданып көргендердің көпшілігі, соның ішінде осы мақаланың авторы мәлімдеген):

$ alias docker=podman

және сіз жұмысты жалғастыра аласыз. Жалпы алғанда, Подманмен жағдай өте қызықты, өйткені егер Kubernetes-тің алғашқы нұсқалары Docker-пен жұмыс істеген болса, шамамен 2015 жылдан бастап, контейнер әлемін стандарттағаннан кейін (OCI - Open Container Initiative) және Docker-ді контейнерге және runC-ге бөлгеннен кейін балама Docker Kubernetes: CRI-O жүйесінде жұмыс істеу үшін әзірленуде. Осыған байланысты Подман Кубернетес қағидаттарына негізделген, оның ішінде контейнерлерді топтастыруға негізделген Docker-ке балама болып табылады, бірақ жобаның негізгі мақсаты - қосымша қызметтерсіз Docker стиліндегі контейнерлерді іске қосу. Белгілі себептерге байланысты үйір режимі жоқ, өйткені әзірлеушілер егер сізге кластер қажет болса, Kubernetes алыңыз деп нақты айтады.

параметр

Centos 7 жүйесіне орнату үшін Extras репозиторийін белсендіріңіз, содан кейін барлығын пәрменмен орнатыңыз:

# yum -y install podman

Басқа мүмкіндіктер

Podman systemd үшін бірліктерді жасай алады, осылайша серверді қайта жүктегеннен кейін контейнерлерді іске қосу мәселесін шешеді. Сонымен қатар, systemd контейнердегі pid 1 ретінде дұрыс жұмыс істейтіні жарияланды. Контейнерлерді құрастыру үшін бөлек құрастыру құралы бар, сонымен қатар үшінші тарап құралдары бар - Docker-compose аналогтары, олар да Kubernetes-үйлесімді конфигурация файлдарын жасайды, сондықтан Podman-дан Kubernetes-ке өту мүмкіндігінше қарапайым.

Подманмен жұмыс

Үйір режимі болмағандықтан (кластер қажет болса, ол Кубернетеске ауысуы керек), біз оны бөлек контейнерлерге жинаймыз.

podman-compose орнату:

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

Подман үшін алынған конфигурация файлы сәл өзгеше, мысалы, біз бөлек томдар бөлімін тікелей қызметтер бөліміне жылжытуға тура келді.

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

Жұмыстың нәтижесі:

# 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

Ол systemd және kubernetes үшін не жасайтынын көрейік, ол үшін подкасттың атын немесе идентификаторын білу керек:

# podman pod ls
POD ID         NAME   STATUS    CREATED          # OF CONTAINERS   INFRA ID
71fc2b2a5c63   root   Running   11 minutes ago   3                 db40ab8bf84b

Кубернетес:

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

жүйелік:

# 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

Өкінішке орай, контейнерлерді іске қосудан басқа, systemd үшін жасалған құрылғы басқа ештеңе жасамайды (мысалы, мұндай қызмет қайта іске қосылғанда ескі контейнерлерді тазалау), сондықтан мұндай нәрселерді өзіңіз қосуға тура келеді.

Негізінде, Podman контейнерлердің не екенін сынап көру, докер құрастыру үшін ескі конфигурацияларды тасымалдау, содан кейін қажет болса, кластерде Кубернетеске бару немесе Docker-ке оңайырақ балама алу үшін жеткілікті.

rkt

Жоба мұрағатқа кетті шамамен алты ай бұрын оны RedHat сатып алғандықтан, мен бұл туралы толығырақ тоқталмаймын. Жалпы алғанда, бұл өте жақсы әсер қалдырды, бірақ Docker-пен салыстырғанда, және одан да көп Подманмен салыстырғанда, ол комбайнға ұқсайды. Сондай-ақ rkt үстіне салынған CoreOS дистрибуциясы болды (бірақ оларда бастапқыда Docker болғанымен), бірақ ол да RedHat сатып алғаннан кейін аяқталды.

Плас

көбірек бір жоба, авторы жай ғана контейнерлерді құрастырып, іске қосқысы келді. Құжаттама мен кодқа қарағанда, автор стандарттарды сақтамады, бірақ жай ғана өзінің іске асыруын жазуды шешті, ол, негізінен, жасады.

қорытындылар

Кубернетеспен жағдай өте қызықты: бір жағынан, Docker көмегімен сіз тіпті клиенттер үшін өндірістік орталарды іске қоса аласыз, кластерді жинай аласыз (3-5 адам), бұл әсіресе шағын командаларға қатысты (XNUMX-XNUMX адам). ) немесе шағын жалпы жүктемемен немесе Kubernetes орнатудың қыр-сырын түсінуге деген құлшынысының болмауы, соның ішінде жоғары жүктемелер үшін.

Podman толық үйлесімділікті қамтамасыз етпейді, бірақ оның бір маңызды артықшылығы бар - Kubernetes-пен үйлесімділік, соның ішінде қосымша құралдар (buildah және басқалар). Сондықтан мен жұмыс құралын таңдауға келесідей қараймын: шағын командалар үшін немесе бюджеті шектеулі - Docker (мүмкін үйір режимі бар), жеке локалхостта өзім үшін әзірлеу үшін - Подман жолдастар және басқалар үшін - Кубернетес.

Мен Docker жағдайының болашақта өзгермейтініне сенімді емеспін, өйткені олар пионерлер, сонымен қатар біртіндеп біртіндеп стандарттауда, бірақ Подман барлық кемшіліктерімен (тек Linux-та жұмыс істейді, кластерлеу жоқ, құрастыру және басқа әрекеттер үшінші тарап шешімдері болып табылады) болашақ айқынырақ, сондықтан мен барлығын осы тұжырымдарды түсініктемелерде талқылауға шақырамын.

PS 3 тамызда біз іске қосамыз»Docker бейне курсыонда сіз оның жұмысы туралы көбірек біле аласыз. Біз оның барлық құралдарын талдаймыз: негізгі абстракциялардан желі параметрлеріне, әртүрлі операциялық жүйелермен және бағдарламалау тілдерімен жұмыс істеудің нюанстарына дейін. Сіз технологиямен танысып, Docker-ті қай жерде және қалай пайдалану керектігін түсінесіз. Біз сондай-ақ ең жақсы тәжірибе жағдайларын бөлісеміз.

Шығаруға дейін алдын ала тапсырыс құны: 5000 рубль. «Docker Video Course» бағдарламасын табуға болады курс бетінде.

Ақпарат көзі: www.habr.com

пікір қалдыру