TL;DR: një artikull i përmbledhjes dhe udhëzimit për krahasimin e ambienteve për ekzekutimin e aplikacioneve në kontejnerë. Do të shqyrtohen mundësitë e Docker dhe sistemeve të tjera të ngjashme.

Pak histori, nga erdhi gjithçka
Historia
Mënyra e parë e njohur për izolimin e aplikacionit është chroot. Thirrja e sistemit me të njëjtin emër siguron ndryshimin e katalogut rrënjësor – kështu duke i siguruar programit që e thirri akses vetëm në skedarët brenda këtij katalogu. Por nëse programit brenda i jepen të drejta superpërdoruesi, potencialisht ai mund të "dali" nga chroot dhe të ketë qasje në sistemin operativ kryesor. Po ashtu, me ndërrimin e katalogut rrënjësor nuk kufizohen burimet e tjera (memoria operative, procesori), si dhe qasja në rrjet.
Mënyra tjetër është ekzekutimi i një sistemi operativ të plotë brenda kontejnerit, përmes mekanizmave të bërthamës së sistemit operativ. Në sisteme të ndryshme operative, kjo metodë quhet ndryshe, por thelbi mbetet i njëjtë – ekzekutimi i disa sistemeve të pavarura operative, secila prej të cilave punon me të njëjtin bërthame si ajo e sistemit operativ kryesor. Këtu përfshihen FreeBSD Jails, Solaris Zones, OpenVZ dhe LXC për Linux. Sigurohet izolimi jo vetëm në hapësirën e diskut, por edhe në burime të tjera, në veçanti çdo kontejner mund të ketë kufizime në kohën e procesorit, memorjen operative, dhe gjerësinë e rrjetit. Në krahasim me chroot, dalja nga kontejneri është më e vështirë, pasi superpërdoruesi në kontejner ka qasje vetëm në përbërësit e kontejnerit, megjithatë për shkak të nevojës për të mbajtur sistemin operativ brenda kontejnerit në një gjendje të përditësuar dhe përdorimin e versioneve të vjetra të bërthamave (e rëndësishme për Linux, më pak për FreeBSD) ekziston një probabilitet që nuk është zero për "thyerjen" e sistemit të izolimit të bërthamës dhe marrjen e aksesit në sistemin operativ kryesor.
Në vend të lançimit të një sistemi operativ të plotë në një kontejner (me sistemin e inicializimit, menaxherin e paketave etj.), është e mundur të iniciohen menjëherë aplikacione, gjëja kryesore është të sigurohet që aplikacionet të kenë këtë mundësi (prania e bibliotekave të nevojshme dhe skedarëve të tjerë). Kjo ide shërbeu si bazë për virtualizimin e aplikacioneve me kontejner, përfaqësuesi më i njohur dhe më i njohur i së cilës është Docker. Krahasuar me sistemet e mëparshme, mekanizmat më fleksibël të izolimit së bashku me mbështetje të ndërtuar për rrjete virtuale midis kontejnerëve dhe ndjekjen e gjendjes së aplikacionit brenda kontejnerit ofruan në fund mundësinë e ndërtimit të një mjedisi të vetëm të unifikuar nga një numër i madh serverësh fizikë për të drejtuar kontejnerët - pa nevojën për menaxhim manual të burimeve.
Docker
Docker është programi më i njohur për kontejnerizimin e aplikacioneve. I shkruar në gjuhën Go, përdor mundësitë standarde të bërthamës Linux - cgroups, namespaces, capabilities etj., si dhe sisteme të skedareve Aufs dhe të tjera të ngjashme për kursimin e hapësirës disk.

Burimi: wikimedia
Arkitektura
Para versionit 1.11, Docker funksiononte si një shërbim i vetëm, i cili kryente të gjitha operacionet me kontejnerët: shkarkimi i imazheve për kontejnerët, nisja e kontejnerëve, trajtimi i kërkesave përmes API. Duke filluar nga versioni 1.11, Docker u ndal në disa pjesë që bashkëveprojnë mes tyre: containerd, për të trajtuar gjithë ciklin e jetës së kontejnerëve (ndarjen e hapësirës disk, shkarkimin e imazheve, punën me rrjetin, nisjen, instalimin dhe mb monitoringun e gjendjes së kontejnerëve) dhe runC, mjedisi i ekzekutimit të kontejnerëve, i bazuar në përdorimin e cgroups dhe mundësive të tjera të bërthamës Linux. Shërbimi i vetë docker mbeti, por tani shërben vetëm për trajtimin e kërkesave përmes API, të cilat përkthehen në containerd.

Instalimi dhe konfigurimi
Mënyra ime e preferuar për të instaluar docker është docker-machine, e cila përveç instalimit dhe konfigurimit të docker në servera të largët (përfshirë nube të ndryshme) ofron mundësinë e punës me sistemet e skedareve të serverëve të largët, si dhe mund të kryejë ekzekutimin e komandave të ndryshme.
Megjithatë, që nga viti 2018 projekti ka almost ndaluar zhvillimin, prandaj instalimin do ta kryejmë në mënyrën standarde për shumicën e shpërndarjeve Linux - duke shtuar repository dhe duke instaluar paketat e nevojshme.
Ky ky po, kjo metode aplikohet gjithashtu kur bëhet instalimi automatizuar, për shembull me ndihmën e Ansible ose sistemeve të ngjashme, por në këtë artikull nuk do ta diskutoj.
Instalimi do të bëhet në CentOS 7, për server do të përdor një makinë virtuale, për instalimin mjafton të kryej komandat më poshtë:
# 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.ioPas instalimit, duhet të aktivizoni shërbimin, ta vendosni në ngarkesë automatikisht:
# systemctl enable docker
# systemctl start docker
# firewall-cmd --zone=public --add-port=2377/tcp --permanentShtesë mund të krijoni një grup docker, ku përdoruesit do të mund të punojnë me docker pa sudo, të konfiguroni regjistrimin, të aktivizoni qasjen në API nga jashtë, pa harruar të konfiguroni më saktë firewall-in (ndalohet gjithçka që nuk është e lejuar, në shembujt më sipër dhe më poshtë kam lënë këtë për thjeshtësi dhe qartësi), por këtu nuk do të ndalem më në detaje.
Mundësi të tjera
Përveç docker machine të përmendur, ekziston gjithashtu docker registry, një mjet për ruajtjen e imazheve për kontejnerët, si dhe docker compose — një mjet për automatizimin e shpërndarjes së aplikacioneve në konteinerë, përdoren skedarët YAML për ndërtimin dhe konfigurimin e kontejnerëve dhe gjërave të tjera të lidhura (për shembull rrjetet, sistemet e skedarëve të përhershëm për ruajtjen e të dhënave).
Po ashtu, me ndihmën e tij mund të organizoni pipeline për CICD. Një mundësi tjetër interesante është puna në modin klaster, i njohur si swarm mode (deri në versionin 1.12 ishte i njohur si docker swarm), që lejon grumbullimin e disa serverëve në një infrastrukturë unike për ekzekutimin e kontejnerëve. Ka mbështetje për rrjetin virtual për të gjithë serverët, ekziston një balancues ngarkese i integruar dhe po ashtu mbështetje për sekrete për kontejnerët.
Skedarët YAML nga docker compose me disa ndryshime mund të përdoren për këto klasterë, duke automatizuar plotësisht mirëmbajtjen e klasterëve të vogla dhe të mesëm për qëllime të ndryshme. Për klasterët më të mëdhenj, preferohet përdorimi i Kubernetes, pasi kostot e mirëmbajtjes së swarm mode mund të kalojnë ato të Kubernetes. Përveç runC si mjedis ekzekutimi për kontejnerët, mund të instalohet, për shembull,
Puna me Docker
Pas instalimit dhe konfigurimit, do të përpiqemi të ndërtojmë një kluster, në të cilin do të vendosim GitLab dhe Docker Registry për ekipin e zhvilluesve. Si servera do të përdor tre makina virtuale, në të cilat gjithashtu do të vendos një sistem të shpërndarë dosjesh GlusterFS, të cilin do ta përdor si ruajtje për volumin e docker-it, për shembull për të nisur një version të qëndrueshëm të docker registry. Komponentët kyç për nisjen: Docker Registry, Postgresql, Redis, GitLab me mbështetje për GitLab Runner mbi Swarm. Postgresql do ta nisë me klasterizim. , prandaj për ruajtjen e të dhënave të Postgresql nuk duhet të përdorim GlusterFS. Të gjitha të dhënat e tjera kritike do të ruhen në GlusterFS.
Për vendosjen e GlusterFS në të gjitha serverat (të cilët quhen node1, node2, node3), duhet të instaloni paketat, të lejoni punën e firewal-it, të krijoni katalogët e nevojshëm:
# 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/fstabPas instalimit, puna për konfigurimin e GlusterFS duhet të vazhdojë nga një nod, për shembull 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 dockerPastaj duhet të montoni volumin e fituar (komandën duhet ta ekzekutoni në të gjithë serverat):
# mount /srv/dockerKonfigurimi i modalitetit swarm bëhet në një nga serverat, i cili do të jetë Lider, të tjerët do të duhet të bashkohen me klasterin, prandaj rezultatin e ekzekutimit të komandës në serverin e parë duhet ta kopjoni dhe ta ekzekutoni në të tjerët.
Konfigurimi fillestar i klasterit, komandën e nis në node1:
# docker swarm init
Swarm initialized: current node (a5jpfrh5uvo7svzz1ajduokyq) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-0c5mf7mvzc7o7vjk0wngno2dy70xs95tovfxbv4tqt9280toku-863hyosdlzvd76trfptd4xnzd xx.xx.xx.xx:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
# docker swarm join-token managerKopjojmë rezultatin e komandës së dytë, e ekzekutojmë në node2 dhe node3:
# docker swarm join --token SWMTKN-x-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxx xx.xx.xx.xx:2377
This node joined a swarm as a manager.Në këtë pikë, konfigurimi paraprak i serverave ka përfunduar, kalojmë në konfigurimin e shërbimeve, komandat për ekzekutim do të përfundojnë nga node1, përveç nëse tregohet ndryshe.
Së pari, do të krijojmë rrjetet për kontejnerët:
# 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 gitlabPastaj etiketojmë serverat, kjo është e nevojshme për lidhjen e disa shërbimeve me serverat:
# docker node update --label-add nodename=node1 node1
# docker node update --label-add nodename=node2 node2
# docker node update --label-add nodename=node3 node3Më pas krijojmë katalogë për ruajtjen e të dhënave etcd, një ruajtje KV që është e nevojshme për Traefik dhe Stolon. Njëlloj si Postgresql, këto do të jenë konteinerë të lidhur me serverat, prandaj këtë komandë e ekzekutojmë në të gjithë serverat:
# mkdir -p /srv/etcdMë pas krijojmë një skedë për konfigurimin e etcd dhe e aplikojmë atë:
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 etcdPas një kohë, kontrollojmë që klasteri etcd është ngritur:
# 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 healthyKrijojmë kataloge për Postgresql, komandën e ekzekutojmë në të gjitha serverat:
# mkdir -p /srv/pgsqlMë pas krijojmë një skedar për konfigurimin e Postgresql:
01pgsql.yml
version: '3.7'
shërbimet:
pgsentinel:
imazh: sorintlab/stolon:master-pg10
komandë:
- 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
rrjetet:
- etcd
- pgsql
shpërndarje:
replika: 3
update_config:
parallelizmi: 1
vonesë: 30s
renditja: stop-first
veprimi në rast dështimi: pause
pgkeeper1:
imazh: sorintlab/stolon:master-pg10
hostname: pgkeeper1
komandë:
- 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
rrjetet:
- etcd
- pgsql
ambient:
- PGDATA=/var/lib/postgresql/data
volumat:
- pgkeeper1:/var/lib/postgresql/data
sekrete:
- pgsql
- pgsql_repl
shpërndarje:
replika: 1
vendosje:
kufizime: [node.labels.nodename == node1]
pgkeeper2:
imazh: sorintlab/stolon:master-pg10
hostname: pgkeeper2
komandë:
- 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
rrjetet:
- etcd
- pgsql
ambient:
- PGDATA=/var/lib/postgresql/data
volumat:
- pgkeeper2:/var/lib/postgresql/data
sekrete:
- pgsql
- pgsql_repl
shpërndarje:
replika: 1
vendosje:
kufizime: [node.labels.nodename == node2]
pgkeeper3:
imazh: sorintlab/stolon:master-pg10
hostname: pgkeeper3
komandë:
- 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
rrjetet:
- etcd
- pgsql
ambient:
- PGDATA=/var/lib/postgresql/data
volumat:
- pgkeeper3:/var/lib/postgresql/data
sekrete:
- pgsql
- pgsql_repl
shpërndarje:
replika: 1
vendosje:
kufizime: [node.labels.nodename == node3]
postgresql:
imazh: sorintlab/stolon:master-pg10
komandë: 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
rrjetet:
- etcd
- pgsql
shpërndarje:
replika: 3
update_config:
parallelizmi: 1
vonesë: 30s
renditja: stop-first
veprimi në rast dështimi: rollback
volumat:
pgkeeper1:
drejtues: lokal
opsionet_e_drejtuesit:
lloji: asnjë
o: lidhje
pajisja: "/srv/pgsql"
pgkeeper2:
drejtues: lokal
opsionet_e_drejtuesit:
lloji: asnjë
o: lidhje
pajisja: "/srv/pgsql"
pgkeeper3:
drejtues: lokal
opsionet_e_drejtuesit:
lloji: asnjë
o: lidhje
pajisja: "/srv/pgsql"
sekrete:
pgsql:
skedar: "/srv/docker/postgres"
pgsql_repl:
skedar: "/srv/docker/replica"
rrjetet:
etcd:
jashtë: e vërtetë
pgsql:
jashtë: e vërtetëKrijojmë sekrete, përdorim skedarin:
# </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 pgsqlPas një kohe (shikojmë rezultatin e komandës docker service ls, që ngjiten të gjitha shërbimet) fillojmë klasterin 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 initKontrollojmë gatishmërinë e klasterit 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
Konfigurojmë traefik për të hapur aksesin në kontejnerët nga jashtë:
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 traefikNisni Klasterin Redis, për këtë krijoni në të gjitha nyjat një katalog për ruajtje:
# mkdir -p /srv/redis05redis.yml
version: '3.7'
services:
redis-master:
image: 'bitnami/redis:latest'
networks:
- redis
ports:
- '6379:6379'
environment:
- REDIS_REPLICATION_MODE=master
- REDIS_PASSWORD=xxxxxxxxxxx
deploy:
mode: global
restart_policy:
condition: any
volumes:
- 'redis:/opt/bitnami/redis/etc/'
redis-replica:
image: 'bitnami/redis:latest'
networks:
- redis
ports:
- '6379'
depends_on:
- redis-master
environment:
- REDIS_REPLICATION_MODE=slave
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_PASSWORD=xxxxxxxxxxx
- REDIS_PASSWORD=xxxxxxxxxxx
deploy:
mode: replicated
replicas: 3
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: any
redis-sentinel:
image: 'bitnami/redis:latest'
networks:
- redis
ports:
- '16379'
depends_on:
- redis-master
- redis-replica
entrypoint: |
bash -c 'bash -s <<EOF
"/bin/bash" -c "cat < /opt/bitnami/redis/etc/sentinel.conf
port 16379
dir /tmp
sentinel monitor master-node redis-master 6379 2
sentinel down-after-milliseconds master-node 5000
sentinel parallel-syncs master-node 1
sentinel failover-timeout master-node 5000
sentinel auth-pass master-node xxxxxxxxxxx
sentinel announce-ip redis-sentinel
sentinel announce-port 16379
EOF"
"/bin/bash" -c "redis-sentinel /opt/bitnami/redis/etc/sentinel.conf"
EOF'
deploy:
mode: global
restart_policy:
condition: any
volumes:
redis:
driver: local
driver_opts:
type: 'none'
o: 'bind'
device: "/srv/redis"
networks:
redis:
external: true# docker stack deploy --compose-file 05redis.yml redisShtojmë Docker Registry:
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 registryDhe dhe final — 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'] = "noreply@example.com"
gitlab_rails['smtp_password'] = "xxxxxxxxx"
gitlab_rails['smtp_domain'] = "example.com"
gitlab_rails['gitlab_email_from'] = 'noreply@example.com'
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_tls'] = true
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_openssl_verify_mode'] = 'peer'
external_url 'http://gitlab.example.com/'
gitlab_rails['gitlab_shell_ssh_port'] = 22222
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 gitlabGjendja përfundimtare e klasterit dhe shërbimeve:
# 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Çfarë mund të përmirësohet akoma? Sigurohuni të konfiguroni Traefik për të punuar me kontejnerët përmes https, shtoni enkriptimin tls për Postgresql dhe Redis. Por në përgjithësi, mund t'ua dorëzojmë tashmë zhvilluesve si PoC. Tani do të shqyrtojmë alternativat ndaj Docker.
Podman
Një motor tjetër mjaft i njohur për të lançuar kontejnerë, të grupuar në Pod-e (pods, grupe kontejnerësh të vendosur së bashku). Në dallim nga Docker, nuk kërkon asnjë shërbim për të lançuar kontejnerët; e gjithë puna bëhet përmes bibliotekës libpod. Po ashtu është shkruar në Go, dhe kërkon një runtime të përputhshëm me OCI për të lançuar kontejnerët, për shembull runC.

Puna me Podman në përgjithësi i ngjan asaj për Docker, deri në pikën që dikush mund ta bëjë këtë (sipërmarrë nga shumë që e kanë provuar, përfshirë autorin e këtij artikulli):
$ alias docker=podmandhe mund të vazhdojme të punojmë. Në përgjithësi, situata me Podman është mjaft interesante, sepse nëse versionet e hershme të Kubernetes punonin me Docker, që nga rreth vitit 2015, pas standardizimit të botës së kontejnerëve (OCI — Open Container Initiative) dhe ndarjen e Docker në containerd dhe runC, është zhvilluar një alternativë e Docker për të ankoruar në Kubernetes: CRI-O. Podman në këtë përputhje është një alternativë e Docker, e ndërtuar sipas parimeve të Kubernetes, përfshirë dhe grupimin e kontejnerëve, por qëllimi kryesor i ekzistencës së projektit është lançimi i kontejnerëve në stilin Docker pa shërbime shtesë. Për arsye të qarta, nuk ka modalitetin swarm, pasi zhvilluesit thjesht thonë se nëse keni nevojë për klaster — merrni Kubernetes.
Instalimi
Për të instaluar në Centos 7 mjafton të aktivizoni repository-n Extras, pas së cilës mund ta instaloni me komandën:
# yum -y install podmanMundësi të tjera
Podman mund të gjenerojë njësitë për systemd, duke zgjidhur kështu problemin e lançimit të kontejnerëve pas rinisjes së serverit. Gjithashtu, është deklaruar funksionimi korrekt i systemd si pid 1 në kontejner. Për ndërtimin e kontejnerëve ka një mjet të veçantë buildah, ka gjithashtu mjete të tjera të jashtme — ekuivalente me docker-compose, që gjithashtu gjenerojnë skedarë konfigurimi të përputhshëm me Kubernetes, kështu që kalimi nga Podman në Kubernetes sa është e mundur, është e thjeshtë.
Puna me Podman
Pasi nuk ka modalitetin swarm (parashikohet kalimi në Kubernetes, nëse nevojitet klaster) — do të grumbullojmë me kontejnerë të ndarë.
Instalojmë podman-compose:
# yum -y install python3-pip
# pip3 install podman-composeSkedari rezultues i konfigurimit për podman paksa ndryshon, kështu që për shembull, na duhej të transferonim një seksion të veçantë volumes direkt në seksionin me shërbimet.
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 upRezultati i punës:
# 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_1Le të shohim se çfarë do të generohet për systemd dhe kubernetes, për këtë duhet të dimë emrin ose ID-në e pod-it:
# podman pod ls
POD ID NAME STATUS CREATED # OF CONTAINERS INFRA ID
71fc2b2a5c63 root Running 11 minutes ago 3 db40ab8bf84bKubernetes:
# 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.targetPër fat të keq, përveç nisjes së konteinerëve, një njësi e gjeneruar për systemd nuk bën asgjë tjetër (për shembull, pastrimin e konteinerëve të vjetër gjatë rinisjes së një shërbimi të tillë), prandaj këto gjëra do të duhet t'i shkruani vetë.
Në parim, Podman është mjaftueshëm për të provuar se çfarë janë konteinerët, për të transferuar konfigurimet e vjetra për docker-compose, pas së cilës mund të kaloni në Kubernetes nëse nevojitet për një grumbull, ose të merrni një alternativë më të thjeshtë për t'u punuar me Docker.
rkt
Projekti rreth gjashtë muaj më parë sepse u ble nga RedHat, prandaj nuk do të ndalem në të më hollësisht. Në përgjithësi, ai la një përshtypje mjaft të mirë, por krahasuar me Docker dhe sidomos me Podman, duket si një kombajn. Ekzistonte gjithashtu një shpërndarje CoreOS, e ndërtuar mbi bazën e rkt (pavarësisht se fillimisht kishin Docker), por mbështetja e saj gjithashtu përfundoi pas blerjes nga RedHat.
Plash
Më shumë , autori i të cilit dëshiroi thjesht të mbledhë dhe të nisë konteinerët. Sipas dokumentacionit dhe kodit — autori nuk ndoqi standardet, por thjesht vendosi të shkruajë implementimin e tij, gjë që në parim e bëri.
Përfundimet
Situata kur ka Kubernetes është shumë interesante: nga njëra anë, me Docker mund të ndërtohet një grumbull (në modin swarm), me të cilin madje mund të nisen mjedise produkti për klientët, kjo është veçanërisht relevante për ekipet e vogla (3-5 persona), ose në rastin e një ngarkese të vogël të përgjithshme, ose mungesës së dëshirës për të kuptuar nuancat e konfigurimit të Kubernetes, përfshirë edhe për ngarkesa të larta.
Podman nuk ofron pajtueshmëri të plotë, por ka një përparësi të rëndësishme — pajtueshmërinë me Kubernetes, përfshirë edhe mjetet shtesë (buildah dhe të tjerë). Prandaj, për të zgjedhur mjetin për punë do ta qas kështu: për ekipe të vogla, ose me buxhet të kufizuar — Docker (me mode të mundshme swarm), për zhvillim për usevet personal në localhost — Podman me shokë, dhe për të gjithë të tjerët — Kubernetes.
Nuk jam i sigurt se situata me Docker do të ndryshojë në të ardhmen, pas të gjithash ata janë pionierë, dhe gjithashtu po standardizohen ngadalë për çdo hap, por e ardhmja e Podman, përkundër të gjitha mangësive të tij (funksionon vetëm në Linux, nuk ka klasterizim, ndërtimi dhe veprime të tjera janë me zgjidhje të jashtme) është më e qartë, prandaj ftoj të gjithë të interesuarit të diskutojnë këto përfundime në komente.
P.S. 3 gusht, nisemi me "", ku do të mund të mësoni më shumë rreth funksionimit të tij. Ne do të analizojmë të gjitha mjetet e tij: nga abstraksionet kryesore deri te parametrat e rrjetit, nuancat e punës me sisteme të ndryshme operative dhe gjuhët e programimit. Do të njiheni me teknologjinë dhe do të kuptoni se ku dhe si është më mirë të përdorni Docker. Gjithashtu do të ndajmë best practice rastet.
Çmimi i parakohshëm deri në lëshim: 5000 r. Mund të njiheni me programin "Videokursit për Docker" .
Burimi: habr.com
