TL;DR: Një udhëzues përmbledhës për krahasimin e kornizave për ekzekutimin e aplikacioneve në kontejnerë. Do të merren parasysh aftësitë e Docker dhe sistemeve të tjera të ngjashme.
Një histori e vogël se nga erdhi e gjitha
Histori
Metoda e parë e njohur për izolimin e një aplikacioni është chroot. Thirrja e sistemit me të njëjtin emër siguron ndryshimin e direktoriumit rrënjë - duke siguruar kështu që programi që e ka thirrur të ketë akses vetëm në skedarët brenda atij drejtorie. Por nëse një programi i jepen privilegje rrënjësore nga brenda, ai potencialisht mund të "shpëtuar" nga chroot dhe të fitojë akses në sistemin kryesor operativ. Gjithashtu, përveç ndryshimit të direktoriumit rrënjë, burimet e tjera (RAM, procesori), si dhe aksesi në rrjet nuk janë të kufizuara.
Metoda tjetër është lëshimi i një sistemi operativ të plotë brenda një kontejneri, duke përdorur mekanizmat e kernelit të sistemit operativ. Kjo metodë quhet ndryshe në sisteme të ndryshme operative, por thelbi është i njëjtë - lëshimi i disa sistemeve operative të pavarura, secila prej të cilave ekzekuton të njëjtin kernel në të cilin funksionon sistemi kryesor operativ. Këto përfshijnë FreeBSD Jails, Solaris Zones, OpenVZ dhe LXC për Linux. Izolimi sigurohet jo vetëm nga hapësira në disk, por edhe nga burime të tjera; në veçanti, çdo kontejner mund të ketë kufizime në kohën e procesorit, RAM-in dhe gjerësinë e brezit të rrjetit. Krahasuar me chroot, largimi nga kontejneri është më i vështirë, pasi superpërdoruesi në kontejner ka qasje vetëm në përmbajtjen e kontejnerit, megjithatë, për shkak të nevojës për të mbajtur të përditësuar sistemin operativ brenda kontejnerit dhe përdorimin e versioneve më të vjetra. e kerneleve (relevante për Linux-in, në një masë më të vogël FreeBSD), ekziston një gjasë jo zero për të "depërtuar" sistemin e izolimit të kernelit dhe për të fituar akses në sistemin kryesor operativ.
Në vend që të nisni një sistem operativ të plotë në një enë (me një sistem inicializimi, menaxher paketash, etj.), Ju mund të nisni aplikacionet menjëherë, gjëja kryesore është t'u jepni aplikacioneve një mundësi të tillë (prania e bibliotekave të nevojshme dhe skedarë të tjerë). Kjo ide shërbeu si bazë për virtualizimin e aplikacioneve të kontejnerizuar, përfaqësuesi më i shquar dhe më i njohur i të cilit është Docker. Krahasuar me sistemet e mëparshme, mekanizmat më fleksibël të izolimit, së bashku me mbështetjen e integruar për rrjetet virtuale midis kontejnerëve dhe gjurmimin e gjendjes së aplikacionit brenda kontejnerit, rezultuan në aftësinë për të ndërtuar një mjedis të vetëm koherent nga një numër i madh serverësh fizikë për funksionimin e kontejnerëve - pa pasur nevojë për menaxhim manual të burimeve.
prerës
Docker është programi më i famshëm i kontejnerizimit të aplikacioneve. I shkruar në gjuhën Go, ai përdor veçoritë standarde të kernelit Linux - cgroups, hapësirat e emrave, aftësitë, etj., si dhe sistemet e skedarëve Aufs dhe të tjera të ngjashme për të kursyer hapësirën në disk.
Burimi: wikimedia
Arkitekturë
Përpara versionit 1.11, Docker punonte si një shërbim i vetëm që kryente të gjitha operacionet me kontejnerë: shkarkimin e imazheve për kontejnerë, lëshimin e kontejnerëve, përpunimin e kërkesave API. Duke filluar me versionin 1.11, Docker u nda në disa pjesë që ndërveprojnë me njëra-tjetrën: kontejneri, për përpunimin e të gjithë ciklit jetësor të kontejnerëve (ndarja e hapësirës në disk, shkarkimi i imazheve, puna me rrjetin, nisja, instalimi dhe monitorimi i gjendjes së kontejnerëve) dhe runC, mjedisi i ekzekutimit të kontejnerit, bazuar në përdorimin e cgroups dhe veçorive të tjera të kernelit Linux. Vetë shërbimi docker mbetet, por tani shërben vetëm për të përpunuar kërkesat API të përkthyera në kontejner.
Instalimi dhe konfigurimi
Mënyra ime e preferuar për të instaluar docker është docker-machine, e cila, përveç instalimit dhe konfigurimit të drejtpërdrejtë të docker-it në serverët në distancë (duke përfshirë retë e ndryshme), bën të mundur punën me sistemet e skedarëve të serverëve në distancë dhe gjithashtu mund të ekzekutojë komanda të ndryshme.
Megjithatë, që nga viti 2018, projekti pothuajse nuk është zhvilluar, kështu që ne do ta instalojmë atë në mënyrën standarde për shumicën e shpërndarjeve Linux - duke shtuar një depo dhe duke instaluar paketat e nevojshme.
Kjo metodë përdoret gjithashtu për instalim të automatizuar, për shembull duke përdorur Ansible ose sisteme të tjera të ngjashme, por unë nuk do ta konsideroj atë në këtë artikull.
Instalimi do të kryhet në Centos 7, unë do të përdor një makinë virtuale si server, për të instaluar thjesht ekzekutoni komandat e mëposhtme:
# 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
Pas instalimit, duhet të filloni shërbimin dhe ta vendosni atë në fillim:
# systemctl enable docker
# systemctl start docker
# firewall-cmd --zone=public --add-port=2377/tcp --permanent
Për më tepër, ju mund të krijoni një grup docker, përdoruesit e të cilit do të jenë në gjendje të punojnë me docker pa sudo, të konfigurojnë regjistrimin, të mundësojnë hyrjen në API nga jashtë dhe mos harroni të konfiguroni murin e zjarrit më saktë (gjithçka që nuk lejohet është e ndaluar në shembujt e mësipërm dhe më poshtë - e kam lënë këtë për thjeshtësi dhe qartësi), por nuk do të hyj në më shumë detaje këtu.
Karakteristika te tjera
Përveç makinës docker të lartpërmendur, ekziston edhe regjistri docker, një mjet për ruajtjen e imazheve për kontejnerë, si dhe docker compose, një mjet për automatizimin e vendosjes së aplikacioneve në kontejnerë, skedarët YAML përdoren për të ndërtuar dhe konfiguruar kontejnerë dhe gjëra të tjera të lidhura (për shembull, rrjetet, sistemet e skedarëve të vazhdueshëm për ruajtjen e të dhënave).
Mund të përdoret gjithashtu për të organizuar transportues për CICD. Një veçori tjetër interesante është puna në modalitetin e grupit, i ashtuquajturi modaliteti swarm (përpara versionit 1.12 njihej si tufa docker), i cili ju lejon të grumbulloni një infrastrukturë të vetme nga disa serverë për drejtimin e kontejnerëve. Ekziston mbështetje për një rrjet virtual në krye të të gjithë serverëve, ka një balancues të integruar të ngarkesës, si dhe mbështetje për sekretet për kontejnerët.
Skedarët YAML nga docker compose, me modifikime të vogla, mund të përdoren për grupime të tilla, duke automatizuar plotësisht mirëmbajtjen e grupimeve të vogla dhe të mesme për qëllime të ndryshme. Për grupime të mëdha, Kubernetes është i preferueshëm, sepse kostot e mirëmbajtjes së modalitetit swarm mund të tejkalojnë ato të Kubernetes. Përveç runC, mund të instaloni, për shembull, si mjedisin e ekzekutimit të kontejnerit
Duke punuar me Docker
Pas instalimit dhe konfigurimit, ne do të përpiqemi të mbledhim një grup në të cilin do të vendosim GitLab dhe Docker Registry për ekipin e zhvillimit. Unë do të përdor tre makina virtuale si serverë, në të cilët do të vendos gjithashtu FS GlusterFS-in e shpërndarë; do ta përdor atë si një ruajtje të vëllimeve docker, për shembull, për të ekzekutuar një version tolerant ndaj gabimeve të regjistrit të dokerit. Komponentët kryesorë për të ekzekutuar: Docker Registry, Postgresql, Redis, GitLab me mbështetje për GitLab Runner në krye të Swarm. Ne do të lançojmë Postgresql me grupim
Për të vendosur GlusterFS në të gjithë serverët (ata quhen node1, node2, node3), duhet të instaloni paketa, të aktivizoni murin e zjarrit dhe të krijoni drejtoritë e nevojshme:
# 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
Pas instalimit, puna për konfigurimin e GlusterFS duhet të vazhdojë nga një nyje, për shembull nyja 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
Pastaj ju duhet të montoni vëllimin që rezulton (komandimi duhet të ekzekutohet në të gjithë serverët):
# mount /srv/docker
Modaliteti swarm është konfiguruar në një nga serverët, i cili do të jetë Leader, pjesa tjetër do të duhet të bashkohet me grupin, kështu që rezultati i ekzekutimit të komandës në serverin e parë do të duhet të kopjohet dhe ekzekutohet në të tjerët.
Konfigurimi fillestar i grupit, unë ekzekutoj komandën 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 manager
Ne kopjojmë rezultatin e komandës së dytë dhe e ekzekutojmë atë 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 serverëve ka përfunduar, le të vazhdojmë me konfigurimin e shërbimeve; komandat që do të ekzekutohen do të nisen nga nyja 1, përveç nëse specifikohet ndryshe.
Para së gjithash, le të krijojmë rrjete për kontejnerë:
# 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
Pastaj ne shënojmë serverët, kjo është e nevojshme për të lidhur disa shërbime me serverët:
# docker node update --label-add nodename=node1 node1
# docker node update --label-add nodename=node2 node2
# docker node update --label-add nodename=node3 node3
Më pas, ne krijojmë direktori për ruajtjen e të dhënave etcd, ruajtjen e KV, e cila është e nevojshme për Traefik dhe Stolon. Ngjashëm me Postgresql, këto do të jenë kontejnerë të lidhur me serverët, kështu që ne ekzekutojmë këtë komandë në të gjithë serverët:
# mkdir -p /srv/etcd
Më pas, krijoni një skedar për të konfiguruar etcd dhe përdorni 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 etcd
Pas ca kohësh, kontrollojmë që grupi etcd është lart:
# 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
Ne krijojmë drejtori për Postgresql, ekzekutojmë komandën në të gjithë serverët:
# mkdir -p /srv/pgsql
Tjetra, krijoni një skedar për të konfiguruar 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
Ne gjenerojmë sekrete dhe 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 pgsql
Pas ca kohësh (shiko daljen e komandës shërbimi docker lsqë të gjitha shërbimet janë në funksion) ne inicializojmë grupin 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
Kontrollimi i gatishmërisë së grupit 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
Ne konfigurojmë traefik për të hapur hyrjen në kontejnerë 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 traefik
Ne nisim Redis Cluster, për ta bërë këtë ne krijojmë një drejtori ruajtjeje në të gjitha nyjet:
# 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
Shto Regjistrin 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
Dhe së fundi - 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
Gjendja përfundimtare e grupit 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ë tjetër mund të përmirësohet? Sigurohuni që të konfiguroni Traefik për të drejtuar kontejnerët mbi https, shtoni enkriptim tls për Postgresql dhe Redis. Por në përgjithësi, ajo tashmë mund t'u jepet zhvilluesve si një PoC. Le të shohim tani alternativat për Docker.
podman
Një tjetër motor mjaft i njohur për drejtimin e kontejnerëve të grupuar sipas pods (pods, grupe kontejnerësh të vendosur së bashku). Ndryshe nga Docker, nuk kërkon ndonjë shërbim për të drejtuar kontejnerët; e gjithë puna kryhet përmes bibliotekës libpod. E shkruar gjithashtu në Go, kërkon një kohë ekzekutimi të pajtueshme me OCI për të ekzekutuar kontejnerët, të tillë si runC.
Puna me Podman në përgjithësi të kujton atë për Docker, deri në pikën që mund ta bësh kështu (siç thuhet nga shumë që e kanë provuar, përfshirë autorin e këtij artikulli):
$ alias docker=podman
dhe mund të vazhdoni të punoni. Në përgjithësi, situata me Podman është shumë interesante, sepse nëse versionet e hershme të Kubernetes funksionuan me Docker, atëherë rreth vitit 2015, pas standardizimit të botës së kontejnerëve (OCI - Open Container Initiative) dhe ndarjes së Docker në kontejner dhe runC, një alternativë ndaj Docker për drejtimin në Kubernetes është zhvilluar: CRI-O. Podman në këtë drejtim është një alternativë ndaj Docker, e ndërtuar mbi parimet e Kubernetes, duke përfshirë grupimin e kontejnerëve, por qëllimi kryesor i projektit është të lëshojë kontejnerë të stilit Docker pa shërbime shtesë. Për arsye të dukshme, nuk ka modalitet tufë, pasi zhvilluesit thonë qartë se nëse keni nevojë për një grup, merrni Kubernetes.
Instalim
Për të instaluar në Centos 7, thjesht aktivizoni depon e Extras dhe më pas instaloni gjithçka me komandën:
# yum -y install podman
Karakteristika te tjera
Podman mund të gjenerojë njësi për systemd, duke zgjidhur kështu problemin e nisjes së kontejnerëve pas një rindezjeje të serverit. Për më tepër, systemd deklarohet se funksionon si duhet si pid 1 në kontejner. Ekziston një mjet i veçantë buildah për ndërtimin e kontejnerëve, ka edhe mjete të palëve të treta - analoge të docker-compose, të cilat gjithashtu gjenerojnë skedarë konfigurimi të pajtueshëm me Kubernetes, kështu që kalimi nga Podman në Kubernetes thjeshtohet sa më shumë që të jetë e mundur.
Duke punuar me Podman
Meqenëse nuk ka modalitet swarm (supozohet të kalojmë në Kubernetes nëse nevojitet një grup), ne do ta mbledhim atë në kontejnerë të veçantë.
Instaloni podman-compose:
# yum -y install python3-pip
# pip3 install podman-compose
Skedari i konfigurimit që rezulton për podman është paksa i ndryshëm, kështu që për shembull na u desh të zhvendosnim një seksion të veçantë vëllimesh direkt në seksionin me shërbime.
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
Rezultati:
# 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
Le të shohim se çfarë gjeneron për systemd dhe kubernetes, për këtë duhet të zbulojmë emrin ose ID-në e 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: {}
Sistemuar:
# 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
Fatkeqësisht, përveç lëshimit të kontejnerëve, njësia e gjeneruar për systemd nuk bën asgjë tjetër (për shembull, pastrimi i kontejnerëve të vjetër kur një shërbim i tillë riniset), kështu që do të duhet të shkruani vetë gjëra të tilla.
Në parim, Podman është i mjaftueshëm për të provuar se cilat janë kontejnerët, transferoni konfigurimet e vjetra për docker-compose dhe më pas lëvizni drejt Kubernetes, nëse keni nevojë për një grup, ose merrni një alternativë më të lehtë për t'u përdorur për Docker.
rkt
Projekt
Pelush
Më shumë
Gjetjet
Situata me Kubernetes është shumë interesante: nga njëra anë, me Docker mund të ndërtoni një grup (në modalitetin swarm), me të cilin mund të ekzekutoni edhe mjedise produkti për klientët, kjo është veçanërisht e vërtetë për ekipet e vogla (3-5 persona) , ose me një ngarkesë të vogël të përgjithshme, ose mungesë dëshire për të kuptuar ndërlikimet e konfigurimit të Kubernetes, duke përfshirë edhe ngarkesat e larta.
Podman nuk ofron pajtueshmëri të plotë, por ka një avantazh të rëndësishëm - pajtueshmërinë me Kubernetes, duke përfshirë mjete shtesë (buildah dhe të tjerët). Prandaj, unë do t'i qasem zgjedhjes së një mjeti për punë si më poshtë: për ekipe të vogla, ose me një buxhet të kufizuar - Docker (me një modalitet të mundshëm tufë), për t'u zhvilluar për veten time në një host personal lokal - shokët Podman, dhe për të gjithë të tjerët - Kubernetes.
Nuk jam i sigurt se situata me Docker nuk do të ndryshojë në të ardhmen, në fund të fundit, ata janë pionierë, dhe gjithashtu gradualisht po standardizohen hap pas hapi, por Podman, me të gjitha mangësitë e tij (punon vetëm në Linux, pa grumbullim, asambleja dhe veprimet e tjera janë zgjidhje të palëve të treta) e ardhmja është më e qartë, ndaj i ftoj të gjithë t'i diskutojnë këto gjetje në komente.
PS Më 3 gusht nisim “
Çmimi para-porosit para lëshimit: 5000 RUB. Ju mund të shikoni programin Docker Video Course
Burimi: www.habr.com