TL;DR: en översiktsartikel-guide som jÀmför miljöer för att köra applikationer i containrar. Möjligheterna med Docker och andra liknande system kommer att diskuteras.

Lite historia, varifrÄn allt kommer
Historien
Det första allmÀnt kÀnda sÀttet att isolera en applikation Àr chroot. Systemanropet med samma namn Àndrar rotkatalogen - pÄ sÄ sÀtt ges programmet som utför det Ätkomst endast till filer inuti den katalogen. Men om programmet inuti ges superanvÀndarbeteenden kan det potentiellt "fly" frÄn chroot och fÄ tillgÄng till det underliggande operativsystemet. Dessutom begrÀnsas inte andra resurser (arbetsminne, processor) eller nÀtverksÄtkomst vid Àndringen av rotkatalogen.
NÀsta metod Àr att köra ett fullt operativsystem inuti containern, tack vare kÀrnans mekanismer i operativsystemet. I olika operativsystem kallas denna metod pÄ olika sÀtt, men principen Àr densamma - att köra flera oberoende operativsystem, dÀr varje körs med samma kÀrna som det grundlÀggande operativsystemet. Detta inkluderar FreeBSD Jails, Solaris Zones, OpenVZ och LXC för Linux. Isoleringen omfattar inte bara diskutrymme, utan Àven andra resurser; varje container kan ha begrÀnsningar för processorutnyttjande, arbetsminne och nÀtverksbandbredd. JÀmfört med chroot Àr det svÄrare att ta sig ut ur containern, eftersom superanvÀndaren i containern har tillgÄng endast till innehÄllet i containern. Men pÄ grund av behovet av att hÄlla operativsystemet inuti containern uppdaterat och anvÀnda Àldre kÀrnversioner (aktuellt för Linux, i mindre utstrÀckning FreeBSD) finns det en icke-noll chans att "bryta" isoleringssystemet i kÀrnan och fÄ tillgÄng till det grundlÀggande operativsystemet.
IstĂ€llet för att köra ett fullt operativsystem i en container (med initieringssystem, paketförvaltare osv.) kan man direkt köra applikationer, det viktigaste Ă€r att ge applikationerna den möjligheten (genom att ha nödvĂ€ndiga bibliotek och andra filer). Denna idĂ© ligger till grund för containerbaserad virtualisering av applikationer, dĂ€r den mest framtrĂ€dande och kĂ€nda representanten Ă€r Docker. JĂ€mfört med tidigare system har mer flexibla isoleringsmekanismer tillsammans med inbyggt stöd för virtuella nĂ€tverk mellan containrar och övervakning av applikationens tillstĂ„nd inuti containern möjliggjort skapandet av en enhetlig miljö frĂ„n ett stort antal fysiska servrar för körning av containrar â utan behov av manuell resursadministration.
Docker
Docker Ă€r den mest kĂ€nda programvaran för containerisering av applikationer. Den Ă€r skriven i Go och anvĂ€nder standardfunktioner i Linux-kĂ€rnan â cgroups, namespaces, capabilities osv., samt filsystem som Aufs och andra liknande för att spara diskutrymme.

KĂ€lla: wikimedia
Arkitektur
Före version 1.11 fungerade Docker som en enda tjÀnst som verkstÀllde alla operationer med containrar: nedladdning av bilder för containrar, körning av containrar, behandling av API-förfrÄgningar. FrÄn och med version 1.11 har Docker delats upp i flera komponenter som interagerar med varandra: containerd, för att hantera hela livscykeln för containrar (tilldelning av diskutrymme, nedladdning av bilder, arbete med nÀtverket, körning, installation och övervakning av tillstÄndet för containrar) och runC, en körmiljö för containrar baserad pÄ anvÀndning av cgroups och andra funktioner i Linux-kÀrnan. TjÀnsten docker finns fortfarande, men nu anvÀnds den endast för att behandla API-förfrÄgningar som översÀtts till containerd.

Installation och konfiguration
Mitt favorit sÀtt att installera docker Àr docker-machine, som förutom sjÀlva installationen och konfigurationen av docker pÄ fjÀrrservrar (inklusive olika moln) ocksÄ ger möjlighet att arbeta med filsystem pÄ fjÀrrservrar, samt kan köra olika kommandon.
Men sedan 2018 har projektet knappt utvecklats, dĂ€rför kommer vi att göra installationen pĂ„ det vanliga sĂ€ttet för de flesta Linux-distributioner â genom att lĂ€gga till ett repository och installera nödvĂ€ndiga paket.
Denna metod anvÀnds ocksÄ vid automatiserad installation, till exempel med Ansible eller liknande system, men jag kommer inte att behandla det i denna artikel.
Installationen kommer att genomföras pÄ CentOS 7, jag kommer att anvÀnda en virtuell maskin som server, för installationen rÀcker det att köra kommandona nedan:
# 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.ioEfter installationen mÄste tjÀnsten startas och lÀggas till vid systemstart:
# systemctl enable docker
# systemctl start docker
# firewall-cmd --zone=public --add-port=2377/tcp --permanentDessutom kan man skapa en docker-grupp dÀr anvÀndare kan arbeta med docker utan sudo, konfigurera loggning, aktivera extern API-Ätkomst, och viktigt - konfigurera brandvÀggen mer specifikt (blockera allt som inte Àr tillÄtet, nÄgot jag utelÀmnar hÀr för enkelhetens skull), men jag kommer inte att gÄ in mer pÄ detaljer hÀr.
Andra möjligheter
Förutom den nÀmnda docker maskinen finns det Àven docker registry, ett verktyg för att lagra bilder för containrar, samt docker compose - ett verktyg för att automatisera distribution av applikationer i containrar, dÀr YAML-filer anvÀnds för att bygga och konfigurera containrar och andra relaterade objekt (som nÀtverk och permanenta filsystem för datalagring).
Med det hÀr verktyget kan man ocksÄ organisera pipelines för CI/CD. En annan intressant funktion Àr arbete i klusterlÀge, sÄ kallat swarm mode (kÀnd som docker swarm före version 1.12), vilket möjliggör att skapa en enhetlig infrastruktur för att köra containrar frÄn flera servrar. Det finns stöd för virtuella nÀtverk över alla servrar, en inbyggd belastningsbalanserare och stöd för hemligheter för containrar.
YAML-filer frÄn docker compose med smÄ Àndringar kan anvÀndas för sÄdana kluster, vilket helt automatiserar underhÄllet av smÄ och medelstora kluster för olika ÀndamÄl. För stora kluster Àr det att föredra att anvÀnda Kubernetes, eftersom underhÄllskostnaderna för swarm mode kan överstiga de för Kubernetes. Utöver runC kan exempelvis
Arbete med Docker
Efter installation och konfiguration ska vi försöka skapa ett kluster dĂ€r vi deployar GitLab och Docker Registry för utvecklarteamet. Jag kommer att anvĂ€nda tre virtuella maskiner som servrar, dĂ€r jag dessutom kommer att deploya ett distribuerat filsystem GlusterFS, som jag kommer att anvĂ€nda som lagring för docker volumes, till exempel för att köra en redundant version av docker registry. Nyckelkomponenterna för att starta Ă€r: Docker Registry, Postgresql, Redis, GitLab med stöd för GitLab Runner ovanpĂ„ Swarm. Vi kommer att starta Postgresql med klustring. , dĂ€rför behöver vi inte anvĂ€nda GlusterFS för att lagra Postgresql-data. Ăvriga kritiska data kommer att lagras pĂ„ GlusterFS.
För att deploya GlusterFS pÄ alla servrar (dessa benÀmns node1, node2, node3) mÄste vi installera paket, tillÄta brandvÀggens arbete och skapa nödvÀndiga kataloger:
# 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/fstabEfter installationen bör arbetet med att konfigurera GlusterFS fortsÀtta frÄn en nod, till exempel 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 dockerDÀrefter mÄste vi montera den skapade volymen (kommandot ska köras pÄ alla servrar):
# mount /srv/dockerKonfigurationen av swarm-lÀget utförs pÄ en av servrarna, som kommer att vara Leader. De andra mÄste ansluta sig till klustret, sÄ resultatet av kommandot pÄ den första servern mÄste kopieras och köras pÄ de övriga.
Den första konfigurationen av klustret, jag kör kommandot pÄ 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 managerVi kopierar resultatet av det andra kommandot och kör det pÄ node2 och node3:
# docker swarm join --token SWMTKN-x-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxx xx.xx.xx.xx:2377
This node joined a swarm as a manager.SÄ hÀr har vi slutfört den preliminÀra konfigurationen av servrarna, vi gÄr vidare till konfigurationen av tjÀnsterna, kommandona för utförande kommer att köras frÄn node1, om inget annat anges.
Det första vi gör Àr att skapa nÀtverk för containrar:
# 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 gitlabDÀrefter mÀrker vi servrarna, detta behövs för att koppla vissa tjÀnster till servrar:
# docker node update --label-add nodename=node1 node1
# docker node update --label-add nodename=node2 node2
# docker node update --label-add nodename=node3 node3Vidare skapar vi kataloger för lagring av etcd-data, KV-lagringen som behövs för Traefik och Stolon. Precis som Postgresql kommer dessa att vara kopplade till servercontainrar, sÄ vi kör detta kommando pÄ alla servrar:
# mkdir -p /srv/etcdDÀrefter skapar vi en fil för konfiguration av etcd och tillÀmpar den:
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 etcdEfter en stund kontrollerar vi att etcd-klustret har startat:
# 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 healthyVi skapar kataloger för Postgresql, kommandot körs pÄ alla servrar:
# mkdir -p /srv/pgsqlDÀrefter skapar vi en fil för konfigurationen av 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: trueVi genererar hemligheter, tillÀmpar filen:
# </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 pgsqlEfter en stund (vi kollar kommandots utdata docker service ls, att alla tjÀnster har startats) initierar vi PostgreSQL-klustret:
# 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 initVi kontrollerar att PostgreSQL-klustret Àr redo:
# 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
Vi konfigurerar Traefik för att öppna Ätkomst till containrar utifrÄn:
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 traefikVi startar Redis-klustret, för detta skapar vi en katalog för lagring pÄ alla noder:
# 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 redisVi lÀgger till 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 registryOch slutligen â 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 gitlabDet slutgiltiga tillstÄndet för klustret och tjÀnsterna:
# 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/tcpVad mer kan förbÀttras? Se till att konfigurera Traefik för att köra containrar över https, lÀgg till tls-kryptering för Postgresql och Redis. Men i stort sett kan det redan lÀmnas till utvecklarna som en PoC. LÄt oss nu titta pÄ alternativa lösningar till Docker.
Podman
En annan ganska kÀnd motor för att köra containrar, grupperade i pods (pods, grupper av containrar som distribueras tillsammans). Till skillnad frÄn Docker krÀver den ingen tjÀnst för att köra containrar, allt arbete utförs via biblioteket libpod. Den Àr ocksÄ skriven i Go och krÀver en OCI-kompatibel runtime för att köra containrar, exempelvis runC.

Arbetet med Podman liknar i stort sett arbetet med Docker, till och med sÄ att man kan göra sÄ hÀr (det har rapporterats av mÄnga testare, inklusive författaren av denna artikel):
$ alias docker=podmanoch man kan fortsĂ€tta arbeta. I stort sett Ă€r situationen med Podman ganska intressant, för om de tidiga versionerna av Kubernetes arbetade med Docker, sĂ„ började det ungefĂ€r 2015, efter standardiseringen av containervĂ€rlden (OCI â Open Container Initiative) och uppdelningen av Docker i containerd och runC, att utvecklas ett alternativ till Docker för att köras i Kubernetes: CRI-O. Podman Ă€r i detta avseende ett alternativ till Docker, byggt pĂ„ principer frĂ„n Kubernetes, inklusive gruppering av containrar, men det huvudsakliga mĂ„let med projektet Ă€r att köra containrar i Docker-stil utan extra tjĂ€nster. Av uppenbara skĂ€l finns inget swarm-lĂ€ge, eftersom utvecklarna tydligt sĂ€ger att om man behöver kluster â ta Kubernetes.
Installation
För installation i Centos 7 rÀcker det med att aktivera Extras-repot, varefter man installerar allt med kommandot:
# yum -y install podmanAndra möjligheter
Podman kan generera enheter för systemd, vilket löser uppgiften att köra containrar efter en serveromstart. Dessutom har det rapporterats att systemd fungerar korrekt som pid 1 i containern. För att bygga containrar finns det ett separat verktyg, buildah, och det finns ocksĂ„ tredjepartsverktyg â analoger till docker-compose, som Ă€ven genererar konfigurationsfiler som Ă€r kompatibla med Kubernetes, sĂ„ övergĂ„ngen frĂ„n Podman till Kubernetes har gjorts sĂ„ enkel som möjligt.
Arbete med Podman
Eftersom det inte finns nĂ„got swarm-lĂ€ge (det förutsĂ€tts att man gĂ„r över till Kubernetes om man behöver kluster) â kommer vi att bygga med separata containrar.
Installera podman-compose:
# yum -y install python3-pip
# pip3 install podman-composeDen resulterande konfigurationsfilen för podman skiljer sig nÄgot, sÄ t.ex. var man tvungen att flytta en separat sektion för volumes direkt till sektionen med tjÀnster.
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 upResultat av arbetet:
# 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_1LÄt oss se vad det genererar för systemd och Kubernetes, först mÄste vi veta namnet eller ID:t pÄ podden:
# 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.targetTyvÀrr gör den genererade enheten för systemd mer Àn att bara starta containrar (till exempel rensa gamla containrar vid omstart av en sÄdan tjÀnst), sÄ sÄdana saker mÄste skrivas in manuellt.
I princip Àr Podman tillrÀckligt för att prova vad containrar Àr, att överföra gamla konfigurationer för docker-compose, och efter det gÄ vidare till Kubernetes om man behöver ett kluster, annars fÄ en enklare alternativ till Docker.
rkt
Projektet ungefÀr för sex mÄnader sedan eftersom det köptes av RedHat, sÄ jag kommer inte att gÄ djupare in pÄ det. Generellt sett gav det ett ganska bra intryck, men jÀmfört med Docker, och speciellt med Podman, framstÄr det som en komplicerad lösning. Det fanns ocksÄ en distribution av CoreOS som byggdes pÄ rkt (Àven om de ursprungligen hade Docker), men dess stöd upphörde ocksÄ efter att RedHat köpte det.
Plash
Mer , vars skapare ville helt enkelt samla och köra containrar. Enligt dokumentationen och koden följde skaparen inte standarder, utan bestÀmde sig för att skriva sin egen implementation, vilket han i princip gjorde.
Slutsatser
Situationen med Kubernetes ser mycket intressant ut: Ä ena sidan kan man med Docker bygga ett kluster (i swarm-lÀget), vilket till och med kan anvÀndas för att köra produktionsmiljöer för kunder, detta Àr sÀrskilt relevant för smÄ team (3-5 personer) eller vid en lÄg total belastning, eller om man inte vill hantera nyanserna i installationen av Kubernetes, sÀrskilt för hög belastning.
Podman erbjuder inte fullstĂ€ndig kompatibilitet, men det har en viktig fördel â kompatibilitet med Kubernetes, inklusive ytterligare verktyg (buildah med flera). DĂ€rför kommer jag att nĂ€rma mig valet av verktyg pĂ„ följande sĂ€tt: för smĂ„ team eller med begrĂ€nsad budget â Docker (eventuellt i swarm-lĂ€ge), för personlig utveckling pĂ„ lokal localhost â Podman med kollegor, och för alla andra â Kubernetes.
Jag Ă€r inte sĂ€ker pĂ„ att situationen med Docker inte kommer att förĂ€ndras i framtiden, de Ă€r trots allt pionjĂ€rer och standardiseras gradvis, men Podman, med alla sina nackdelar (fungerar endast pĂ„ Linux, ingen klustring, byggande och andra Ă„tgĂ€rder â genom tredjepartslösningar), har en tydligare framtid, dĂ€rför inbjuder jag alla intresserade att diskutera dessa slutsatser i kommentarerna.
P.S. 3 augusti lanserar vi "", dÀr man kan fÄ mer information om dess funktion. Vi kommer att gÄ igenom alla dess verktyg: frÄn grundlÀggande abstraktioner till nÀtverksinstÀllningar, nyanser inom olika operativsystem och programmeringssprÄk. Du kommer att bekanta dig med teknologin och förstÄ var och hur du bÀst kan anvÀnda Docker. Vi kommer ocksÄ att dela best practice-fall.
FörhandsbestÀllning fram till lansering: 5000 kr. Programmet för "Videokurs om Docker" kan ses .
KĂ€lla: habr.com
