TL;DR: Artikel ikhtisar - panduan untuk membandingkan lingkungan untuk menjalankan aplikasi dalam container. Kemungkinan Docker dan sistem serupa lainnya akan dipertimbangkan.
Sedikit sejarah dari mana semua itu berasal
Cerita
Cara terkenal pertama untuk mengisolasi aplikasi adalah chroot. Panggilan sistem dengan nama yang sama memberikan perubahan pada direktori root - sehingga memberikan akses ke program yang memanggilnya, akses hanya ke file di dalam direktori ini. Namun jika program diberikan hak pengguna super di dalamnya, program tersebut berpotensi "melarikan diri" dari chroot dan mendapatkan akses ke sistem operasi utama. Selain itu, selain mengubah direktori root, sumber daya lain (RAM, prosesor), serta akses ke jaringan, tidak dibatasi.
Cara selanjutnya adalah meluncurkan sistem operasi lengkap di dalam container, menggunakan mekanisme kernel sistem operasi. Metode ini disebut berbeda di sistem operasi yang berbeda, tetapi intinya sama - menjalankan beberapa sistem operasi independen, yang masing-masing berjalan pada kernel yang sama yang menjalankan sistem operasi utama. Ini termasuk Penjara FreeBSD, Solaris Zones, OpenVZ, dan LXC untuk Linux. Isolasi disediakan tidak hanya untuk ruang disk, tetapi juga untuk sumber daya lainnya, khususnya, setiap wadah mungkin memiliki batasan waktu prosesor, RAM, bandwidth jaringan. Dibandingkan dengan chroot, meninggalkan container lebih sulit, karena pengguna super di dalam container hanya memiliki akses ke bagian dalam container, namun karena kebutuhan untuk selalu memperbarui sistem operasi di dalam container dan penggunaan kernel lama. versi (relevan untuk Linux, pada tingkat lebih rendah FreeBSD), ada kemungkinan besar untuk "menerobos" sistem isolasi kernel dan mendapatkan akses ke sistem operasi utama.
Daripada meluncurkan sistem operasi lengkap dalam sebuah wadah (dengan sistem inisialisasi, manajer paket, dll.), aplikasi dapat segera diluncurkan, yang utama adalah menyediakan aplikasi dengan kesempatan ini (keberadaan perpustakaan yang diperlukan dan file lain). Ide ini menjadi dasar untuk virtualisasi aplikasi dalam container, perwakilan yang paling menonjol dan terkenal adalah Docker. Dibandingkan dengan sistem sebelumnya, mekanisme isolasi yang lebih fleksibel, bersama dengan dukungan bawaan untuk jaringan virtual antar container dan status aplikasi di dalam container, menghasilkan kemampuan untuk membangun lingkungan holistik tunggal dari sejumlah besar server fisik untuk menjalankan container - tanpa kebutuhan untuk manajemen sumber daya manual.
Buruh pelabuhan
Docker adalah perangkat lunak containerisasi aplikasi yang paling terkenal. Ditulis dalam bahasa Go, ia menggunakan kemampuan reguler kernel Linux - cgroup, namespace, kemampuan, dll., serta sistem file Aufs dan sejenisnya untuk menghemat ruang disk.
Sumber: wikimedia
Arsitektur
Sebelum versi 1.11, Docker bekerja sebagai layanan tunggal yang melakukan semua operasi dengan container: mengunduh image untuk container, meluncurkan container, memproses permintaan API. Sejak versi 1.11, Docker telah dipecah menjadi beberapa bagian yang berinteraksi satu sama lain: containerd, untuk menangani seluruh siklus hidup container (alokasi ruang disk, pengunduhan image, jaringan, peluncuran, instalasi, dan pemantauan status container) dan runC , runtime container, berdasarkan penggunaan cgroups dan fitur lain dari kernel Linux. Layanan docker sendiri tetap ada, namun sekarang hanya berfungsi untuk memproses permintaan API yang disiarkan ke containerd.
Instalasi dan konfigurasi
Cara favorit saya untuk menginstal buruh pelabuhan adalah mesin buruh pelabuhan, yang selain menginstal dan mengkonfigurasi buruh pelabuhan secara langsung di server jarak jauh (termasuk berbagai cloud), memungkinkan Anda bekerja dengan sistem file server jarak jauh, dan juga dapat menjalankan berbagai perintah.
Namun, sejak 2018, proyek ini hampir tidak dikembangkan, jadi kami akan menginstalnya dengan cara yang biasa dilakukan pada sebagian besar distribusi Linux - dengan menambahkan repositori dan menginstal paket yang diperlukan.
Metode ini juga digunakan untuk instalasi otomatis, misalnya menggunakan Ansible atau sistem serupa lainnya, tetapi saya tidak akan membahasnya dalam artikel ini.
Instalasi akan dilakukan pada Centos 7, saya akan menggunakan virtual machine sebagai server, untuk instalasi cukup jalankan perintah dibawah ini :
# 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
Setelah instalasi, Anda perlu memulai layanan, memasukkannya ke dalam autoload:
# systemctl enable docker
# systemctl start docker
# firewall-cmd --zone=public --add-port=2377/tcp --permanent
Selain itu, Anda dapat membuat grup buruh pelabuhan, yang penggunanya akan dapat bekerja dengan buruh pelabuhan tanpa sudo, mengatur logging, mengaktifkan akses ke API dari luar, jangan lupa untuk menyempurnakan firewall (semua yang tidak diperbolehkan adalah dilarang dalam contoh di atas dan di bawah - saya menghilangkannya untuk kesederhanaan dan visualisasi), tetapi saya tidak akan membahas lebih detail di sini.
Fitur lainnya
Selain mesin buruh pelabuhan di atas, terdapat juga docker registry, alat untuk menyimpan image untuk container, serta docker composer - alat untuk mengotomatisasi penerapan aplikasi dalam container, file YAML digunakan untuk membangun dan mengkonfigurasi container dan hal terkait lainnya (misalnya, jaringan, sistem file persisten untuk menyimpan data).
Ini juga dapat digunakan untuk mengatur saluran pipa untuk CICD. Fitur menarik lainnya adalah bekerja dalam mode cluster, yang disebut mode gerombolan (sebelum versi 1.12 dikenal sebagai gerombolan buruh pelabuhan), yang memungkinkan Anda merakit satu infrastruktur dari beberapa server untuk menjalankan container. Ada dukungan untuk jaringan virtual di atas semua server, ada penyeimbang beban bawaan, serta dukungan untuk rahasia untuk container.
File YAML dari docker composer dapat digunakan untuk klaster tersebut dengan sedikit modifikasi, yang sepenuhnya mengotomatiskan pemeliharaan klaster kecil dan menengah untuk berbagai tujuan. Untuk klaster yang besar, Kubernetes lebih disukai karena biaya pemeliharaan mode gerombolan dapat melebihi biaya yang dikeluarkan Kubernetes. Selain runC, sebagai lingkungan eksekusi untuk container, Anda dapat menginstal, misalnya
Bekerja dengan Docker
Setelah instalasi dan konfigurasi, kami akan mencoba membangun sebuah cluster di mana kami akan menerapkan GitLab dan Docker Registry untuk tim pengembangan. Sebagai server, saya akan menggunakan tiga mesin virtual, di mana saya juga akan menyebarkan FS terdistribusi GlusterFS, saya akan menggunakannya sebagai penyimpanan volume buruh pelabuhan, misalnya, untuk menjalankan versi registri buruh pelabuhan yang aman dari kegagalan. Komponen utama yang harus dijalankan: Docker Registry, Postgresql, Redis, GitLab dengan dukungan untuk GitLab Runner di atas Swarm. Postgresql akan diluncurkan dengan clustering
Untuk menyebarkan GlusterFS di semua server (disebut node1, node2, node3), Anda perlu menginstal paket, mengaktifkan firewall, membuat direktori yang diperlukan:
# 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
Setelah instalasi, pekerjaan konfigurasi GlusterFS harus dilanjutkan dari satu node, misalnya 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
Maka Anda perlu memasang volume yang dihasilkan (perintah harus dijalankan di semua server):
# mount /srv/docker
Mode gerombolan dikonfigurasi di salah satu server, yang akan menjadi Pemimpin, sisanya harus bergabung dengan cluster, sehingga hasil menjalankan perintah di server pertama perlu disalin dan dijalankan di server lainnya.
Pengaturan cluster awal, saya menjalankan perintah di 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
Salin hasil perintah kedua, jalankan pada node2 dan node3:
# docker swarm join --token SWMTKN-x-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxx xx.xx.xx.xx:2377
This node joined a swarm as a manager.
Ini menyelesaikan konfigurasi awal server, mari mulai mengkonfigurasi layanan, perintah yang akan dieksekusi akan diluncurkan dari node1, kecuali ditentukan lain.
Pertama-tama, mari buat jaringan untuk container:
# 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
Kemudian kami menandai servernya, ini diperlukan untuk mengikat beberapa layanan ke server:
# docker node update --label-add nodename=node1 node1
# docker node update --label-add nodename=node2 node2
# docker node update --label-add nodename=node3 node3
Selanjutnya kita membuat direktori untuk menyimpan data etcd, penyimpanan KV yang dibutuhkan Traefik dan Stolon. Mirip dengan Postgresql, ini akan menjadi container yang terikat ke server, jadi kami menjalankan perintah ini di semua server:
# mkdir -p /srv/etcd
Selanjutnya, buat file untuk mengkonfigurasi etcd dan terapkan:
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
Setelah beberapa saat, kami memeriksa apakah cluster etcd telah muncul:
# 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
Buat direktori untuk Postgresql, jalankan perintah di semua server:
# mkdir -p /srv/pgsql
Selanjutnya, buat file untuk mengkonfigurasi 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
Kami menghasilkan rahasia, menerapkan file:
# </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
Beberapa waktu kemudian (lihat output dari perintah layanan buruh pelabuhan lsbahwa semua layanan telah meningkat) inisialisasi cluster 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
Memeriksa kesiapan cluster 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
Kami mengkonfigurasi traefik untuk membuka akses ke container dari luar:
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
Kami memulai Redis Cluster, untuk ini kami membuat direktori penyimpanan di semua node:
# 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
Tambahkan Registri 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
Dan terakhir - 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
Status akhir klaster dan layanan:
# 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
Apa lagi yang bisa ditingkatkan? Pastikan untuk mengonfigurasi Traefik agar berfungsi dengan wadah https, tambahkan enkripsi tls untuk Postgresql dan Redis. Namun secara umum, Anda sudah bisa memberikannya kepada pengembang sebagai PoC. Sekarang mari kita lihat alternatif selain Docker.
tukang pod
Mesin lain yang cukup terkenal untuk menjalankan container yang dikelompokkan berdasarkan pod (pod, grup container yang dikerahkan bersama). Tidak seperti Docker, ia tidak memerlukan layanan apa pun untuk menjalankan container, semua pekerjaan dilakukan melalui perpustakaan libpod. Juga ditulis di Go, memerlukan runtime yang sesuai dengan OCI untuk menjalankan container seperti runC.
Bekerja dengan Podman secara umum mirip dengan Docker, sejauh Anda dapat melakukannya seperti ini (diklaim oleh banyak orang yang telah mencobanya, termasuk penulis artikel ini):
$ alias docker=podman
dan kamu bisa terus bekerja. Secara umum, situasi dengan Podman sangat menarik, karena jika versi awal Kubernetes bekerja dengan Docker, maka sejak sekitar tahun 2015, setelah standarisasi dunia container (OCI - Open Container Initiative) dan membagi Docker menjadi containerd dan runC, sebuah alternatif untuk Docker sedang dikembangkan untuk dijalankan di Kubernetes: CRI-O. Podman dalam hal ini adalah alternatif dari Docker, dibangun berdasarkan prinsip Kubernetes, termasuk pengelompokan container, tetapi tujuan utama proyek ini adalah menjalankan container bergaya Docker tanpa layanan tambahan. Untuk alasan yang jelas, tidak ada mode gerombolan, karena pengembang dengan jelas mengatakan bahwa jika Anda memerlukan cluster, gunakan Kubernetes.
Instalasi
Untuk install di Centos 7 cukup aktifkan repositori Extras, lalu install semuanya dengan perintah:
# yum -y install podman
Fitur lainnya
Podman dapat menghasilkan unit untuk systemd, sehingga memecahkan masalah memulai container setelah server di-boot ulang. Selain itu, systemd dinyatakan berfungsi dengan benar sebagai pid 1 dalam wadah. Untuk membangun container, ada alat buildah terpisah, ada juga alat pihak ketiga - analog dari docker-compose, yang juga menghasilkan file konfigurasi yang kompatibel dengan Kubernetes, sehingga transisi dari Podman ke Kubernetes sesederhana mungkin.
Bekerja dengan Podman
Karena tidak ada mode gerombolan (seharusnya beralih ke Kubernetes jika diperlukan cluster), kami akan merakitnya dalam wadah terpisah.
Instal komposisi podman:
# yum -y install python3-pip
# pip3 install podman-compose
File konfigurasi yang dihasilkan untuk podman sedikit berbeda, misalnya kita harus memindahkan bagian volume terpisah langsung ke bagian layanan.
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
Hasil pekerjaan:
# 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
Mari kita lihat apa yang akan dihasilkannya untuk systemd dan kubernetes, untuk ini kita perlu mengetahui nama atau id dari pod:
# podman pod ls
POD ID NAME STATUS CREATED # OF CONTAINERS INFRA ID
71fc2b2a5c63 root Running 11 minutes ago 3 db40ab8bf84b
Kubernet:
# 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
Sayangnya, selain menjalankan container, unit yang dihasilkan untuk systemd tidak melakukan apa pun (misalnya, membersihkan container lama saat layanan tersebut dimulai ulang), jadi Anda harus menambahkan sendiri hal-hal tersebut.
Pada prinsipnya, Podman cukup mencoba apa itu container, mentransfer konfigurasi lama untuk pembuatan buruh pelabuhan, dan kemudian beralih ke Kubernetes, jika perlu, di sebuah cluster, atau mendapatkan alternatif Docker yang lebih mudah digunakan.
rkt
Proyek
Cepuk
Lebih
Temuan
Situasi dengan Kubernetes sangat menarik: di satu sisi, dengan Docker, Anda dapat merakit sebuah cluster (dalam mode gerombolan), yang dengannya Anda bahkan dapat menjalankan lingkungan produksi untuk klien, hal ini terutama berlaku untuk tim kecil (3-5 orang) ), atau dengan beban keseluruhan yang kecil, atau kurangnya keinginan untuk memahami seluk-beluk pengaturan Kubernetes, termasuk untuk beban tinggi.
Podman tidak menyediakan kompatibilitas penuh, tetapi memiliki satu keunggulan penting - kompatibilitas dengan Kubernetes, termasuk alat tambahan (buildah dan lainnya). Oleh karena itu, saya akan mendekati pilihan alat untuk bekerja sebagai berikut: untuk tim kecil, atau dengan anggaran terbatas - Docker (dengan kemungkinan mode gerombolan), untuk pengembangan untuk saya sendiri di localhost pribadi - kawan Podman, dan untuk semua orang lainnya - Kubernet.
Saya tidak yakin situasi dengan Docker tidak akan berubah di masa depan, lagipula, mereka adalah pionir, dan juga perlahan-lahan melakukan standarisasi langkah demi langkah, tetapi Podman, dengan segala kekurangannya (hanya berfungsi di Linux, tidak ada clustering, perakitan dan tindakan lainnya merupakan keputusan pihak ketiga) masa depan lebih jelas, jadi saya mengundang semua orang untuk mendiskusikan temuan ini di komentar.
PS Pada tanggal 3 Agustus kami meluncurkan "
Biaya pemesanan di muka sebelum rilis: 5000 rubel. Program "Kursus Video Docker" dapat ditemukan
Sumber: www.habr.com