Docker dan semuanya, semuanya, semuanya

TL;DR: Artikel ikhtisar - panduan untuk membandingkan lingkungan untuk menjalankan aplikasi dalam container. Kemungkinan Docker dan sistem serupa lainnya akan dipertimbangkan.

Docker dan semuanya, semuanya, semuanya

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.

Docker dan semuanya, semuanya, semuanya
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.

Docker dan semuanya, semuanya, semuanya

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 Kontainer kata

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 Stolon, jadi Anda tidak perlu menggunakan GlusterFS untuk menyimpan data Postgresql. Data penting lainnya akan disimpan di GlusterFS.

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.

Docker dan semuanya, semuanya, semuanya

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 pergi ke arsip sekitar enam bulan yang lalu karena RedHat membelinya, jadi saya tidak akan membahasnya lebih detail. Secara umum, ini meninggalkan kesan yang sangat baik, tetapi dibandingkan dengan Docker, dan terlebih lagi dengan Podman, ini terlihat seperti gabungan. Ada juga distribusi CoreOS yang dibangun di atas rkt (meskipun awalnya memiliki Docker), tetapi itu juga berakhir setelah pembelian RedHat.

Cepuk

Lebih satu proyek, yang penulisnya hanya ingin membuat dan menjalankan container. Dilihat dari dokumentasi dan kodenya, penulis tidak mengikuti standar, tetapi hanya memutuskan untuk menulis implementasinya sendiri, yang pada prinsipnya dia lakukan.

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 "Kursus video Dockerdi mana Anda dapat mempelajari lebih lanjut tentang karyanya. Kami akan menganalisis semua alatnya: dari abstraksi dasar hingga parameter jaringan, nuansa bekerja dengan berbagai sistem operasi dan bahasa pemrograman. Anda akan mengenal teknologinya dan memahami di mana dan bagaimana cara terbaik menggunakan Docker. Kami juga akan membagikan kasus praktik terbaik.

Biaya pemesanan di muka sebelum rilis: 5000 rubel. Program "Kursus Video Docker" dapat ditemukan di halaman kursus.

Sumber: www.habr.com

Tambah komentar