TL;DR: Konteynerlerde uygulama çalıştırmaya yönelik çerçeveleri karşılaştırmaya yönelik genel bakış kılavuzu. Docker ve benzeri sistemlerin yetenekleri dikkate alınacaktır.
Her şeyin nereden geldiğine dair küçük bir tarih
Öykü
Bir uygulamayı izole etmek için iyi bilinen ilk yöntem chroot'tur. Aynı isimdeki sistem çağrısı, kök dizinin değiştirilmesini sağlar; böylece onu çağıran programın yalnızca o dizin içindeki dosyalara erişebilmesini sağlar. Ancak bir programa dahili olarak kök ayrıcalıkları verilirse, potansiyel olarak chroot'tan "kaçabilir" ve ana işletim sistemine erişim sağlayabilir. Ayrıca kök dizini değiştirmenin yanı sıra diğer kaynaklar (RAM, işlemci) ve ağ erişimi de sınırlı değildir.
Bir sonraki yöntem, işletim sistemi çekirdeğinin mekanizmalarını kullanarak tam teşekküllü bir işletim sistemini bir konteyner içinde başlatmaktır. Bu yöntem farklı işletim sistemlerinde farklı şekilde adlandırılır, ancak özü aynıdır - her biri ana işletim sisteminin çalıştığı çekirdeği çalıştıran birkaç bağımsız işletim sisteminin başlatılması. Bunlara FreeBSD Hapishaneleri, Solaris Bölgeleri, OpenVZ ve Linux için LXC dahildir. Yalıtım yalnızca disk alanıyla değil aynı zamanda diğer kaynaklarla da sağlanır; özellikle her konteynerin işlemci süresi, RAM ve ağ bant genişliği konusunda sınırlamaları olabilir. Chroot ile karşılaştırıldığında konteynerden ayrılmak daha zordur, çünkü konteynerdeki süper kullanıcı yalnızca konteynerin içeriğine erişebilir, ancak konteynerin içindeki işletim sistemini güncel tutma ihtiyacı ve eski sürümlerin kullanılması nedeniyle çekirdeklerin sayısı (Linux için, daha az ölçüde FreeBSD ile ilgilidir), çekirdek izolasyon sistemini "kırma" ve ana işletim sistemine erişim kazanma olasılığı sıfırdan fazladır.
Bir kapta tam teşekküllü bir işletim sistemini başlatmak yerine (bir başlatma sistemi, paket yöneticisi vb. ile), uygulamaları hemen başlatabilirsiniz, asıl önemli olan uygulamalara böyle bir fırsat sağlamaktır (gerekli kitaplıkların varlığı) ve diğer dosyalar). Bu fikir, en önde gelen ve tanınmış temsilcisi Docker olan konteynerleştirilmiş uygulama sanallaştırmasının temelini oluşturdu. Önceki sistemlerle karşılaştırıldığında, daha esnek izolasyon mekanizmaları, konteynerler arasındaki sanal ağlar için yerleşik destek ve konteyner içindeki uygulama durumu takibi ile birleştiğinde, konteynerleri çalıştırmak için çok sayıda fiziksel sunucudan tek bir tutarlı ortam oluşturma becerisiyle sonuçlandı. manuel kaynak yönetimine gerek kalmadan.
liman işçisi
Docker, en ünlü uygulama konteynerleştirme yazılımıdır. Go dilinde yazılmış olup, disk alanından tasarruf etmek için Linux çekirdeğinin standart özelliklerini (cgroups, ad alanları, yetenekler vb.) ve ayrıca Aufs dosya sistemlerini ve bunun gibi diğerlerini kullanır.
Kaynak: wikimedia
Mimari
1.11 sürümünden önce Docker, konteynerlerle ilgili tüm işlemleri gerçekleştiren tek bir hizmet olarak çalışıyordu: konteynerler için görüntülerin indirilmesi, konteynerlerin başlatılması, API isteklerinin işlenmesi. 1.11 sürümünden başlayarak Docker, birbiriyle etkileşime giren birkaç parçaya bölündü: konteynerlerin tüm yaşam döngüsünü işlemek için konteynerd (disk alanı ayırma, görüntüleri indirme, ağ ile çalışma, konteynerlerin başlatılması, kurulması ve durumunun izlenmesi) ve cgroup'ların ve Linux çekirdeğinin diğer özelliklerinin kullanımına dayalı konteyner yürütme ortamı olan runC. Docker hizmetinin kendisi kalıyor ancak artık yalnızca konteynere çevrilen API isteklerini işlemeye hizmet ediyor.
Kurulum ve konfigürasyon
Docker'ı kurmanın en sevdiğim yolu, docker'ı uzak sunuculara (çeşitli bulutlar dahil) doğrudan kurup yapılandırmanın yanı sıra, uzak sunucuların dosya sistemleriyle çalışmayı mümkün kılan ve ayrıca çeşitli komutları çalıştırabilen docker-machine'dir.
Ancak, 2018'den bu yana proje neredeyse hiç geliştirilmedi, bu nedenle onu çoğu Linux dağıtımı için standart yöntemle kuracağız - bir depo ekleyerek ve gerekli paketleri kurarak.
Bu yöntem, örneğin Ansible veya diğer benzer sistemler kullanılarak otomatik kurulum için de kullanılır, ancak bu makalede bunu dikkate almayacağım.
Kurulum Centos 7 üzerinde gerçekleştirilecek, sunucu olarak sanal bir makine kullanacağım, kurulum için aşağıdaki komutları çalıştırmanız yeterli:
# 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
Kurulumdan sonra hizmeti başlatmanız ve başlangıç durumuna getirmeniz gerekir:
# systemctl enable docker
# systemctl start docker
# firewall-cmd --zone=public --add-port=2377/tcp --permanent
Ek olarak, kullanıcıları sudo olmadan docker ile çalışabilecek, günlük kaydı ayarlayabilecek, API'ye dışarıdan erişimi etkinleştirebilecek ve güvenlik duvarını daha hassas bir şekilde yapılandırmayı unutmayın (izin verilmeyen her şeye) sahip olacak bir docker grubu oluşturabilirsiniz. Yukarıdaki ve aşağıdaki örneklerde yasaklanmıştır - basitlik ve netlik açısından bunu atladım), ancak burada daha fazla ayrıntıya girmeyeceğim.
Diğer özellikleri
Yukarıda belirtilen docker makinesine ek olarak, konteynerler için görüntüleri depolamak için bir araç olan docker kayıt defteri ve ayrıca konteynerlerdeki uygulamaların dağıtımını otomatikleştirmek için bir araç olan docker compose da vardır, YAML dosyaları konteynerler oluşturmak ve yapılandırmak için kullanılır ve diğer ilgili şeyler (örneğin ağlar, verilerin depolanması için kalıcı dosya sistemleri).
Ayrıca CICD'ye yönelik konveyörleri organize etmek için de kullanılabilir. Bir başka ilginç özellik de, konteynerleri çalıştırmak için birkaç sunucudan tek bir altyapı oluşturmanıza olanak tanıyan, sürü modu adı verilen (sürüm 1.12'den önce, docker sürüsü olarak biliniyordu) küme modunda çalışmaktır. Tüm sunucuların üstünde bir sanal ağ desteği var, yerleşik bir yük dengeleyicinin yanı sıra konteynerler için sırlar desteği de var.
Docker compose'un YAML dosyaları, küçük değişikliklerle bu tür kümeler için kullanılabilir ve çeşitli amaçlar için küçük ve orta ölçekli kümelerin bakımını tamamen otomatikleştirir. Büyük kümeler için Kubernetes tercih edilir çünkü sürü modunun bakım maliyetleri Kubernetes'inkini aşabilir. RunC'ye ek olarak, örneğin konteyner yürütme ortamı olarak da kurulum yapabilirsiniz.
Docker'la çalışma
Kurulum ve konfigürasyonun ardından geliştirme ekibi için GitLab ve Docker Registry’yi konuşlandıracağımız bir küme oluşturmaya çalışacağız. Sunucu olarak üç sanal makine kullanacağım ve bunlara ek olarak dağıtılmış FS GlusterFS'yi dağıtacağım; bunu, örneğin docker kayıt defterinin hataya dayanıklı bir sürümünü çalıştırmak için docker birimleri depolama alanı olarak kullanacağım. Çalıştırılacak temel bileşenler: Swarm'ın yanı sıra GitLab Runner desteğiyle Docker Registry, Postgresql, Redis, GitLab. Postgresql'i kümeleme ile başlatacağız
GlusterFS'yi tüm sunuculara dağıtmak için (bunlara düğüm1, düğüm2, düğüm3 denir), paketleri kurmanız, güvenlik duvarını etkinleştirmeniz ve gerekli dizinleri oluşturmanız gerekir:
# 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
Kurulumdan sonra GlusterFS'yi yapılandırma çalışmalarına bir düğümden, örneğin düğüm1'den devam edilmelidir:
# 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
Daha sonra ortaya çıkan birimi bağlamanız gerekir (komutun tüm sunucularda yürütülmesi gerekir):
# mount /srv/docker
Sürü modu, Lider olacak sunuculardan birinde yapılandırılmıştır, geri kalanının kümeye katılması gerekecektir, bu nedenle komutun ilk sunucuda yürütülmesinin sonucunun diğerlerine kopyalanması ve yürütülmesi gerekecektir.
İlk küme kurulumunda, düğüm1'de komutu çalıştırıyorum:
# 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
İkinci komutun sonucunu kopyalayıp düğüm2 ve düğüm3'te çalıştırıyoruz:
# docker swarm join --token SWMTKN-x-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxx xx.xx.xx.xx:2377
This node joined a swarm as a manager.
Bu noktada sunucuların ön konfigürasyonu tamamlandı, servislerin kurulumuna geçelim; çalıştırılacak komutlar aksi belirtilmediği sürece node1’den çalıştırılacaktır.
Öncelikle konteynerler için ağlar oluşturalım:
# 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
Daha sonra sunucuları işaretliyoruz, bu bazı hizmetleri sunuculara bağlamak için gereklidir:
# docker node update --label-add nodename=node1 node1
# docker node update --label-add nodename=node2 node2
# docker node update --label-add nodename=node3 node3
Daha sonra Traefik ve Stolon için gerekli olan KV depolama alanı olan etcd verilerini depolamak için dizinler oluşturuyoruz. Postgresql'e benzer şekilde bunlar sunuculara bağlı kaplar olacaktır, dolayısıyla bu komutu tüm sunucularda çalıştırıyoruz:
# mkdir -p /srv/etcd
Daha sonra, etcd'yi yapılandırmak ve kullanmak için bir dosya oluşturun:
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
Bir süre sonra etcd kümesinin çalışır durumda olup olmadığını kontrol ediyoruz:
# docker exec $(docker ps | awk '/etcd/ {print $1}') etcdctl member list
ade526d28b1f92f7: name=etcd1 peerURLs=http://etcd1:2380 clientURLs=http://etcd1:2379 isLeader=false
bd388e7810915853: name=etcd3 peerURLs=http://etcd3:2380 clientURLs=http://etcd3:2379 isLeader=false
d282ac2ce600c1ce: name=etcd2 peerURLs=http://etcd2:2380 clientURLs=http://etcd2:2379 isLeader=true
# docker exec $(docker ps | awk '/etcd/ {print $1}') etcdctl cluster-health
member ade526d28b1f92f7 is healthy: got healthy result from http://etcd1:2379
member bd388e7810915853 is healthy: got healthy result from http://etcd3:2379
member d282ac2ce600c1ce is healthy: got healthy result from http://etcd2:2379
cluster is healthy
Postgresql için dizinler oluşturuyoruz, komutu tüm sunucularda yürütüyoruz:
# mkdir -p /srv/pgsql
Ardından Postgresql'i yapılandırmak için bir dosya oluşturun:
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
Sırları oluşturuyoruz ve dosyayı kullanıyoruz:
# </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
Bir süre sonra (komutun çıktısına bakın) Liman işçisi hizmeti lstüm hizmetlerin çalıştığından emin olun) Postgresql kümesini başlatıyoruz:
# docker exec $(docker ps | awk '/pgkeeper/ {print $1}') stolonctl --cluster-name=stolon-cluster --store-backend=etcdv3 --store-endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 init
Postgresql kümesinin hazır olup olmadığının kontrol edilmesi:
# docker exec $(docker ps | awk '/pgkeeper/ {print $1}') stolonctl --cluster-name=stolon-cluster --store-backend=etcdv3 --store-endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 status
=== Active sentinels ===
ID LEADER
26baa11d false
74e98768 false
a8cb002b true
=== Active proxies ===
ID
4d233826
9f562f3b
b0c79ff1
=== Keepers ===
UID HEALTHY PG LISTENADDRESS PG HEALTHY PG WANTEDGENERATION PG CURRENTGENERATION
pgkeeper1 true pgkeeper1:5432 true 2 2
pgkeeper2 true pgkeeper2:5432 true 2 2
pgkeeper3 true pgkeeper3:5432 true 3 3
=== Cluster Info ===
Master Keeper: pgkeeper3
===== Keepers/DB tree =====
pgkeeper3 (master)
├─pgkeeper2
└─pgkeeper1
Traefik'i konteynerlere dışarıdan erişim açacak şekilde yapılandırıyoruz:
03traefik.yml
version: '3.7'
services:
traefik:
image: traefik:latest
command: >
--log.level=INFO
--providers.docker=true
--entryPoints.web.address=:80
--providers.providersThrottleDuration=2
--providers.docker.watch=true
--providers.docker.swarmMode=true
--providers.docker.swarmModeRefreshSeconds=15s
--providers.docker.exposedbydefault=false
--accessLog.bufferingSize=0
--api=true
--api.dashboard=true
--api.insecure=true
networks:
- traefik
ports:
- 80:80
volumes:
- /var/run/docker.sock:/var/run/docker.sock
deploy:
replicas: 3
placement:
constraints:
- node.role == manager
preferences:
- spread: node.id
labels:
- traefik.enable=true
- traefik.http.routers.traefik.rule=Host(`traefik.example.com`)
- traefik.http.services.traefik.loadbalancer.server.port=8080
- traefik.docker.network=traefik
networks:
traefik:
external: true
# docker stack deploy --compose-file 03traefik.yml traefik
Redis Cluster'ı başlatıyoruz, bunu yapmak için tüm düğümlerde bir depolama dizini oluşturuyoruz:
# mkdir -p /srv/redis
05redis.yml
version: '3.7'
services:
redis-master:
image: 'bitnami/redis:latest'
networks:
- redis
ports:
- '6379:6379'
environment:
- REDIS_REPLICATION_MODE=master
- REDIS_PASSWORD=xxxxxxxxxxx
deploy:
mode: global
restart_policy:
condition: any
volumes:
- 'redis:/opt/bitnami/redis/etc/'
redis-replica:
image: 'bitnami/redis:latest'
networks:
- redis
ports:
- '6379'
depends_on:
- redis-master
environment:
- REDIS_REPLICATION_MODE=slave
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_PASSWORD=xxxxxxxxxxx
- REDIS_PASSWORD=xxxxxxxxxxx
deploy:
mode: replicated
replicas: 3
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: any
redis-sentinel:
image: 'bitnami/redis:latest'
networks:
- redis
ports:
- '16379'
depends_on:
- redis-master
- redis-replica
entrypoint: |
bash -c 'bash -s <<EOF
"/bin/bash" -c "cat <<EOF > /opt/bitnami/redis/etc/sentinel.conf
port 16379
dir /tmp
sentinel monitor master-node redis-master 6379 2
sentinel down-after-milliseconds master-node 5000
sentinel parallel-syncs master-node 1
sentinel failover-timeout master-node 5000
sentinel auth-pass master-node xxxxxxxxxxx
sentinel announce-ip redis-sentinel
sentinel announce-port 16379
EOF"
"/bin/bash" -c "redis-sentinel /opt/bitnami/redis/etc/sentinel.conf"
EOF'
deploy:
mode: global
restart_policy:
condition: any
volumes:
redis:
driver: local
driver_opts:
type: 'none'
o: 'bind'
device: "/srv/redis"
networks:
redis:
external: true
# docker stack deploy --compose-file 05redis.yml redis
Docker Kaydı Ekle:
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
Ve son olarak - 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
Cluster ve servislerin son durumu:
# 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
Başka ne geliştirilebilir? Traefik'i konteynerleri https üzerinden çalıştıracak şekilde yapılandırdığınızdan, Postgresql ve Redis için tls şifrelemesi eklediğinizden emin olun. Ancak genel olarak geliştiricilere zaten PoC olarak verilebiliyor. Şimdi Docker'ın alternatiflerine bakalım.
podman
Bölmelere (bölmeler, birlikte konuşlandırılan konteyner grupları) göre gruplandırılmış kapları çalıştırmak için oldukça iyi bilinen bir başka motor. Docker'ın aksine, konteynerleri çalıştırmak için herhangi bir hizmete ihtiyaç duymaz; tüm işler libpod kütüphanesi aracılığıyla yapılır. Ayrıca Go'da yazılmış olup, kapsayıcıları çalıştırmak için runC gibi OCI uyumlu bir çalışma zamanı gerektirir.
Podman'la çalışmak genel olarak Docker'ınkine benziyor, o kadar ki bunu şu şekilde yapabilirsiniz (bu makalenin yazarı da dahil olmak üzere bunu deneyen birçok kişi tarafından belirtildiği gibi):
$ alias docker=podman
ve çalışmaya devam edebilirsiniz. Genel olarak Podman'ın durumu çok ilginç çünkü Kubernetes'in ilk sürümleri Docker ile çalıştıysa, o zaman 2015 civarında, konteyner dünyasının standartlaştırılmasından (OCI - Açık Konteyner Girişimi) ve Docker'ın konteynerd ve runC olarak bölünmesinden sonra, Kubernetes'te çalıştırmak için Docker'a bir alternatif geliştiriliyor: CRI-O. Bu bakımdan Podman, konteynerlerin gruplandırılması da dahil olmak üzere Kubernetes ilkeleri üzerine inşa edilmiş Docker'a bir alternatiftir, ancak projenin asıl amacı Docker tarzı konteynerleri ek hizmetler olmadan başlatmaktır. Açık nedenlerden dolayı, sürü modu yoktur, çünkü geliştiriciler bir kümeye ihtiyacınız varsa Kubernetes'i almanızı açıkça söylüyorlar.
Montaj
Centos 7'ye kurulum yapmak için Ekstralar deposunu etkinleştirmeniz ve ardından her şeyi şu komutla kurmanız yeterlidir:
# yum -y install podman
Diğer özellikleri
Podman, systemd için birimler oluşturabilir, böylece sunucu yeniden başlatıldıktan sonra kapsayıcıları başlatma sorununu çözebilir. Ek olarak, systemd'nin kapta pid 1 olarak düzgün çalıştığı bildirildi. Kapsayıcılar oluşturmak için ayrı bir buildah aracı var, ayrıca Kubernetes ile uyumlu yapılandırma dosyaları oluşturan docker-compose analogları gibi üçüncü taraf araçlar da var, böylece Podman'dan Kubernetes'e geçiş mümkün olduğu kadar basitleştirildi.
Podman'la çalışmak
Swarm modu olmadığı için (cluster ihtiyacı varsa Kubernetes'e geçmemiz gerekiyor) ayrı konteynerlerde toplayacağız.
Podman-compose'u yükleyin:
# yum -y install python3-pip
# pip3 install podman-compose
Podman için ortaya çıkan konfigürasyon dosyası biraz farklıdır, bu nedenle örneğin ayrı bir hacimler bölümünü doğrudan hizmetlerin bulunduğu bölüme taşımak zorunda kaldık.
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
Sonuç:
# podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
da53da946c01 docker.io/gitlab/gitlab-runner:alpine run --user=gitlab... About a minute ago Up About a minute ago 0.0.0.0:22222->22/tcp, 0.0.0.0:80->80/tcp root_gitlab-runner_1
781c0103c94a docker.io/gitlab/gitlab-ce:latest /assets/wrapper About a minute ago Up About a minute ago 0.0.0.0:22222->22/tcp, 0.0.0.0:80->80/tcp root_gitlab_1
Systemd ve kubernetes için neler ürettiğini görelim, bunun için pod'un adını veya kimliğini bulmamız gerekiyor:
# podman pod ls
POD ID NAME STATUS CREATED # OF CONTAINERS INFRA ID
71fc2b2a5c63 root Running 11 minutes ago 3 db40ab8bf84b
Kubernet'ler:
# 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: {}
Sistemd:
# 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
Ne yazık ki, systemd için oluşturulan birim, konteynerleri başlatmak dışında başka hiçbir şey yapmaz (örneğin, böyle bir hizmet yeniden başlatıldığında eski konteynerleri temizlemek), dolayısıyla bu tür şeyleri kendiniz yazmanız gerekecektir.
Prensip olarak Podman, konteynerlerin ne olduğunu denemek, docker-compose için eski yapılandırmaları aktarmak ve ardından bir kümeye ihtiyacınız varsa Kubernetes'e geçmek veya Docker'a kullanımı daha kolay bir alternatif almak için yeterlidir.
rkt
Proje
çarpma
başka
Bulgular
Kubernetes ile ilgili durum çok ilginç: bir yandan Docker ile müşteriler için ürün ortamlarını bile çalıştırabileceğiniz bir küme (sürü modunda) oluşturabilirsiniz, bu özellikle küçük ekipler (3-5 kişi) için geçerlidir. veya küçük bir toplam yük ile veya yüksek yükler de dahil olmak üzere Kubernetes kurulumunun inceliklerini anlama arzusunun olmaması.
Podman tam uyumluluk sağlamaz, ancak önemli bir avantajı vardır: ek araçlar (buildah ve diğerleri) dahil olmak üzere Kubernetes ile uyumluluk. Bu nedenle, iş için bir araç seçimine şu şekilde yaklaşacağım: küçük ekipler için veya sınırlı bir bütçeyle - Docker (olası bir sürü moduyla), kişisel bir yerel ana bilgisayarda kendim geliştirmek için - Podman yoldaşlar ve diğer herkes için - Kubernet'ler.
Docker'la ilgili durumun gelecekte değişmeyeceğinden emin değilim, sonuçta onlar öncüler ve yavaş yavaş adım adım standartlaştırılıyorlar, ancak Podman tüm eksikliklerine rağmen (yalnızca Linux'ta çalışıyor, kümeleme yok, montaj ve diğer eylemler üçüncü taraf çözümleridir) gelecek daha net, bu yüzden herkesi bu bulguları yorumlarda tartışmaya davet ediyorum.
PS 3 Ağustos'ta başlıyoruz "
Yayınlanmadan önce ön sipariş fiyatı: 5000 RUB. Docker Video Course programını görüntüleyebilirsiniz
Kaynak: habr.com