TL;DR: una guia general per comparar marcs per executar aplicacions en contenidors. Es tindran en compte les capacitats de Docker i altres sistemes similars.
Una petita història d'on va sortir tot
Història
El primer mètode conegut per aïllar una aplicació és chroot. La trucada del sistema del mateix nom garanteix que es canvia el directori arrel, assegurant així que el programa que l'ha cridat només té accés als fitxers d'aquest directori. Però si un programa té privilegis d'arrel internament, pot "escapar" del chroot i accedir al sistema operatiu principal. A més, a més de canviar el directori arrel, altres recursos (RAM, processador), així com l'accés a la xarxa, no estan limitats.
El següent mètode és llançar un sistema operatiu complet dins d'un contenidor, utilitzant els mecanismes del nucli del sistema operatiu. Aquest mètode s'anomena de manera diferent en diferents sistemes operatius, però l'essència és la mateixa: llançar diversos sistemes operatius independents, cadascun dels quals executa el mateix nucli en què s'executa el sistema operatiu principal. Aquests inclouen les presons FreeBSD, Solaris Zones, OpenVZ i LXC per a Linux. L'aïllament està garantit no només per l'espai en disc, sinó també per altres recursos; en particular, cada contenidor pot tenir limitacions en el temps del processador, la memòria RAM i l'amplada de banda de la xarxa. En comparació amb chroot, sortir del contenidor és més difícil, ja que el superusuari del contenidor només té accés al contingut del contenidor, però, per la necessitat de mantenir el sistema operatiu dins del contenidor actualitzat i l'ús de versions anteriors. dels nuclis (rellevants per a Linux, en menor mesura FreeBSD), hi ha una probabilitat diferent de zero de "sfondre" el sistema d'aïllament del nucli i obtenir accés al sistema operatiu principal.
En lloc de llançar un sistema operatiu complet en un contenidor (amb un sistema d'inicialització, gestor de paquets, etc.), podeu llançar aplicacions immediatament, el més important és oferir a les aplicacions aquesta oportunitat (la presència de les biblioteques necessàries). i altres fitxers). Aquesta idea va servir de base per a la virtualització d'aplicacions en contenidors, el representant més destacat i conegut de les quals és Docker. En comparació amb els sistemes anteriors, els mecanismes d'aïllament més flexibles, juntament amb el suport integrat per a xarxes virtuals entre contenidors i el seguiment de l'estat de l'aplicació dins del contenidor, van donar com a resultat la capacitat de crear un únic entorn coherent a partir d'un gran nombre de servidors físics per executar contenidors. sense necessitat de gestió manual de recursos.
estibador
Docker és el programari de contenidorització d'aplicacions més famós. Escrit en l'idioma Go, utilitza les característiques estàndard del nucli de Linux: cgroups, espais de noms, capacitats, etc., així com sistemes de fitxers Aufs i altres per estalviar espai al disc.
Font: wikimedia
arquitectura
Abans de la versió 1.11, Docker funcionava com un servei únic que realitzava totes les operacions amb contenidors: descàrrega d'imatges per a contenidors, llançament de contenidors, processament de sol·licituds d'API. A partir de la versió 1.11, Docker es va dividir en diverses parts que interactuen entre elles: containerd, per processar tot el cicle de vida dels contenidors (assignar espai en disc, descarregar imatges, treballar amb la xarxa, llançar, instal·lar i controlar l'estat dels contenidors) i runC, l'entorn d'execució de contenidors, basat en l'ús de cgroups i altres característiques del nucli Linux. El servei Docker en si es manté, però ara només serveix per processar sol·licituds d'API traduïdes a containerd.
Instal·lació i configuració
La meva manera preferida d'instal·lar docker és docker-machine, que, a més d'instal·lar i configurar directament docker en servidors remots (inclosos diversos núvols), permet treballar amb sistemes de fitxers de servidors remots i també pot executar diverses ordres.
Tanmateix, des del 2018, el projecte gairebé no s'ha desenvolupat, per la qual cosa l'instal·larem de la manera estàndard per a la majoria de distribucions de Linux: afegint un repositori i instal·lant els paquets necessaris.
Aquest mètode també s'utilitza per a la instal·lació automatitzada, per exemple utilitzant Ansible o altres sistemes similars, però no ho tindré en compte en aquest article.
La instal·lació es durà a terme a Centos 7, faré servir una màquina virtual com a servidor, per instal·lar només cal que executeu les ordres següents:
# 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
Després de la instal·lació, heu d'iniciar el servei i posar-lo a l'inici:
# systemctl enable docker
# systemctl start docker
# firewall-cmd --zone=public --add-port=2377/tcp --permanent
A més, podeu crear un grup docker, els usuaris del qual podran treballar amb docker sense sudo, configurar el registre, habilitar l'accés a l'API des de l'exterior i no oblideu configurar el tallafoc amb més precisió (tot el que no estigui permès). està prohibit als exemples anteriors i següents; ho vaig ometre per simplicitat i claredat), però no entraré en més detalls aquí.
Altres característiques
A més de la màquina docker esmentada anteriorment, també hi ha el registre docker, una eina per emmagatzemar imatges per a contenidors, així com la composició docker, una eina per automatitzar el desplegament d'aplicacions en contenidors, els fitxers YAML s'utilitzen per construir i configurar contenidors. i altres coses relacionades (per exemple, xarxes, sistemes de fitxers persistents per a l'emmagatzematge de dades).
També es pot utilitzar per organitzar transportadors per CICD. Una altra característica interessant és treballar en mode clúster, l'anomenat mode swarm (abans de la versió 1.12 es coneixia com a docker swarm), que permet muntar una única infraestructura a partir de diversos servidors per executar contenidors. Hi ha suport per a una xarxa virtual a la part superior de tots els servidors, hi ha un equilibrador de càrrega integrat, així com suport per a secrets per als contenidors.
Els fitxers YAML de Docker Compose, amb petites modificacions, es poden utilitzar per a aquests clústers, automatitzant completament el manteniment de clústers petits i mitjans per a diversos propòsits. Per a clústers grans, Kubernetes és preferible perquè els costos de manteniment del mode eixam poden superar els de Kubernetes. A més de runC, podeu instal·lar, per exemple, com a entorn d'execució del contenidor
Treballant amb Docker
Després de la instal·lació i configuració, intentarem muntar un clúster en el qual desplegarem GitLab i Docker Registry per a l'equip de desenvolupament. Faré servir tres màquines virtuals com a servidors, en els quals, addicionalment, desplegaré el FS GlusterFS distribuït; el faré servir com a emmagatzematge de volums docker, per exemple, per executar una versió tolerant a errors del registre docker. Components clau per executar: Docker Registry, Postgresql, Redis, GitLab amb suport per a GitLab Runner a la part superior de Swarm. Llançarem Postgresql amb clustering
Per implementar GlusterFS a tots els servidors (s'anomenen node1, node2, node3), heu d'instal·lar paquets, habilitar el tallafoc i crear els directoris necessaris:
# 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
Després de la instal·lació, el treball en la configuració de GlusterFS s'ha de continuar des d'un node, per exemple 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 docker
A continuació, heu de muntar el volum resultant (l'ordre s'ha d'executar a tots els servidors):
# mount /srv/docker
El mode eixam es configura en un dels servidors, que serà el Leader, la resta s'haurà d'unir al clúster, per tant caldrà copiar i executar en els altres el resultat d'executar l'ordre al primer servidor.
Configuració inicial del clúster, executo l'ordre al 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
Copiem el resultat de la segona ordre i l'executem al node2 i al node3:
# docker swarm join --token SWMTKN-x-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxx xx.xx.xx.xx:2377
This node joined a swarm as a manager.
En aquest punt, s'ha completat la configuració preliminar dels servidors, procedim a la configuració dels serveis; les ordres a executar s'executaran des del node1, tret que s'especifiqui el contrari.
En primer lloc, creem xarxes per als contenidors:
# 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
Després marquem els servidors, això és necessari per vincular alguns serveis als servidors:
# docker node update --label-add nodename=node1 node1
# docker node update --label-add nodename=node2 node2
# docker node update --label-add nodename=node3 node3
A continuació, creem directoris per emmagatzemar dades etcd, emmagatzematge KV, que és necessari per a Traefik i Stolon. De manera similar a Postgresql, aquests seran contenidors lligats a servidors, de manera que executem aquesta ordre a tots els servidors:
# mkdir -p /srv/etcd
A continuació, creeu un fitxer per configurar etcd i utilitzeu-lo:
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
Després d'un temps, comprovem que el clúster etcd estigui activat:
# 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
Creem directoris per a Postgresql, executem l'ordre a tots els servidors:
# mkdir -p /srv/pgsql
A continuació, creeu un fitxer per configurar 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
Generem secrets i fem servir el fitxer:
# </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
Després d'un temps (vegeu la sortida de l'ordre servei docker lsque tots els serveis estiguin activats) inicialitzem el clúster 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
Comprovació de la preparació del clúster 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
Configurem traefik per obrir l'accés als contenidors des de l'exterior:
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
Llencem Redis Cluster, per fer-ho creem un directori d'emmagatzematge a tots els nodes:
# 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
Afegeix el registre 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
I finalment - 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
Estat final del clúster i dels serveis:
# 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
Què més es pot millorar? Assegureu-vos de configurar Traefik per executar contenidors sobre https, afegiu el xifratge tls per a Postgresql i Redis. Però, en general, ja es pot donar als desenvolupadors com a PoC. Vegem ara les alternatives a Docker.
Podman
Un altre motor força conegut per fer funcionar contenidors agrupats per beines (pods, grups de contenidors desplegats junts). A diferència de Docker, no requereix cap servei per executar contenidors; tot el treball es fa a través de la biblioteca libpod. També escrit a Go, requereix un temps d'execució compatible amb OCI per executar contenidors, com ara runC.
Treballar amb Podman en general recorda això de Docker, fins al punt que podeu fer-ho així (com diuen molts que ho han provat, inclòs l'autor d'aquest article):
$ alias docker=podman
i pots continuar treballant. En general, la situació amb Podman és molt interessant, perquè si les primeres versions de Kubernetes funcionaven amb Docker, llavors cap al 2015, després de l'estandardització del món dels contenidors (OCI - Open Container Initiative) i la divisió de Docker en containerd i runC, s'ha desenvolupat una alternativa a Docker per executar-se a Kubernetes: CRI-O. Podman en aquest sentit és una alternativa a Docker, basada en els principis de Kubernetes, inclosa l'agrupació de contenidors, però l'objectiu principal del projecte és llançar contenidors a l'estil Docker sense serveis addicionals. Per raons òbvies, no hi ha mode eixam, ja que els desenvolupadors diuen clarament que si necessiteu un clúster, preneu Kubernetes.
Instal · lació
Per instal·lar-lo a Centos 7, només cal que activeu el repositori d'Extres i, a continuació, instal·leu-ho tot amb l'ordre:
# yum -y install podman
Altres característiques
Podman pot generar unitats per a systemd, resolent així el problema d'iniciar contenidors després d'un reinici del servidor. A més, es declara que systemd funciona correctament com a pid 1 al contenidor. Hi ha una eina de construcció separada per construir contenidors, també hi ha eines de tercers: anàlegs de docker-compose, que també generen fitxers de configuració compatibles amb Kubernetes, de manera que la transició de Podman a Kubernetes es simplifica al màxim.
Treballant amb Podman
Com que no hi ha mode eixam (se suposa que hem de canviar a Kubernetes si cal un clúster), el recollirem en contenidors separats.
Instal·leu podman-compose:
# yum -y install python3-pip
# pip3 install podman-compose
El fitxer de configuració resultant per a podman és lleugerament diferent, de manera que, per exemple, hem hagut de moure una secció de volums independent directament a la secció amb serveis.
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
Resultat:
# 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
Vegem què genera per a systemd i kubernetes, per això hem d'esbrinar el nom o id del 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: {}
Sistema:
# 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
Malauradament, a part de llançar contenidors, la unitat generada per a systemd no fa res més (per exemple, netejar contenidors antics quan es reinicia aquest servei), de manera que haureu d'escriure aquestes coses vosaltres mateixos.
En principi, Podman n'hi ha prou per provar què són els contenidors, transferir configuracions antigues per a docker-compose i després avançar cap a Kubernetes, si necessiteu un clúster, o obtenir una alternativa més fàcil d'utilitzar a Docker.
rkt
Projecte
Flash
Més
Troballes
La situació amb Kubernetes és molt interessant: d'una banda, amb Docker es pot construir un clúster (en mode eixam), amb el qual fins i tot es poden executar entorns de producte per a clients, això és especialment cert per a equips petits (3-5 persones). , o amb una petita càrrega general o manca de ganes d'entendre les complexitats de la configuració de Kubernetes, fins i tot per a càrregues elevades.
Podman no ofereix una compatibilitat total, però té un avantatge important: la compatibilitat amb Kubernetes, incloses eines addicionals (buildah i altres). Per tant, abordaré l'elecció d'una eina per treballar de la següent manera: per a equips petits o amb un pressupost limitat: Docker (amb un possible mode d'eixam), per desenvolupar-me en un host local personal: camarades Podman i per a tots els altres. - Kubernetes.
No estic segur que la situació amb Docker no canviarà en el futur, al cap i a la fi, són pioners, i també s'estan estandarditzant a poc a poc, però Podman, per totes les seves mancances (funciona només a Linux, sense clúster, muntatge i altres accions són solucions de tercers) el futur és més clar, així que convido a tothom a discutir aquestes troballes als comentaris.
PS El 3 d'agost estrenen “
Preu de reserva abans del llançament: 5000 RUB. Podeu veure el programa del curs de vídeo Docker
Font: www.habr.com