Docker ug tanan, tanan, tanan

TL; DR: Usa ka kinatibuk-ang artikulo - usa ka giya sa pagtandi sa mga palibot alang sa pagpadagan sa mga aplikasyon sa mga sudlanan. Ang mga posibilidad sa Docker ug uban pang susama nga mga sistema pagaisipon.

Docker ug tanan, tanan, tanan

Usa ka gamay nga kasaysayan kung diin gikan ang tanan

История

Ang una nga nahibal-an nga paagi aron mahimulag ang usa ka aplikasyon mao ang chroot. Ang sistema nga tawag sa parehas nga ngalan naghatag usa ka pagbag-o sa direktoryo sa ugat - sa ingon naghatag pag-access sa programa nga nagtawag niini, pag-access lamang sa mga file sa sulod niini nga direktoryo. Apan kung ang programa gihatagan og mga katungod sa superuser sa sulod, mahimo kini nga "makaikyas" gikan sa chroot ug maka-access sa main operating system. Dugang pa, dugang sa pagbag-o sa root directory, ang ubang mga kapanguhaan (RAM, processor), ingon man ang pag-access sa network, dili limitado.

Ang sunod nga paagi mao ang paglansad sa usa ka hingpit nga operating system sa sulod sa sudlanan, gamit ang mga mekanismo sa kernel sa operating system. Kini nga pamaagi gitawag nga lahi sa lainlaing mga operating system, apan ang esensya parehas - nagpadagan sa daghang mga independente nga operating system, nga ang matag usa nagdagan sa parehas nga kernel nga nagpadagan sa panguna nga operating system. Naglakip kini sa FreeBSD Jails, Solaris Zones, OpenVZ, ug LXC para sa Linux. Gihatag ang pag-inusara dili lamang alang sa wanang sa disk, apan alang usab sa ubang mga kahinguhaan, labi na, ang matag sulud mahimo’g adunay mga pagdili sa oras sa processor, RAM, bandwidth sa network. Kung itandi sa chroot, ang pagbiya sa sudlanan mas lisud, tungod kay ang superuser sa sudlanan adunay access lamang sa sulod sa sudlanan, bisan pa, tungod sa panginahanglan nga ipadayon ang operating system sa sulod sa sudlanan nga hangtod karon ug ang paggamit sa daan nga kernel. mga bersyon (may kalabutan alang sa Linux, sa usa ka gamay nga gidak-on FreeBSD), adunay usa ka non-zero ang posibilidad nga "makalusot" sa kernel isolation system ug makaangkon og access sa main operating system.

Imbis nga maglansad sa usa ka bug-os nga operating system sa usa ka sudlanan (nga adunay usa ka sistema sa pagsugod, usa ka manager sa package, ug uban pa.), Ang mga aplikasyon mahimong ilunsad dayon, ang panguna nga butang mao ang paghatag sa mga aplikasyon niini nga oportunidad (ang presensya sa mga kinahanglan nga librarya ug ubang mga file). Kini nga ideya nagsilbi nga basehan alang sa containerized application virtualization, ang labing inila ug inila nga representante niini mao ang Docker. Kung itandi sa nangaging mga sistema, ang labi ka nabag-o nga mga mekanismo sa pag-inusara, kauban ang built-in nga suporta alang sa mga virtual nga network sa taliwala sa mga sulud ug kahimtang sa aplikasyon sa sulod sa usa ka sulud, nagresulta sa katakus sa paghimo sa usa ka holistic nga palibot gikan sa daghang mga pisikal nga server aron makadagan ang mga sudlanan - nga wala. ang panginahanglan alang sa manwal nga pagdumala sa kapanguhaan.

Docker

Ang Docker mao ang labing inila nga software sa containerization sa aplikasyon. Gisulat sa Go nga pinulongan, kini naggamit sa regular nga kapabilidad sa Linux kernel - cgroups, namespaces, kapabilidad, ug uban pa, ingon man sa Aufs file system ug uban pa nga susama sa pagluwas sa disk space.

Docker ug tanan, tanan, tanan
Tinubdan: wikimedia

arkitektura

Sa wala pa ang bersyon 1.11, ang Docker nagtrabaho isip usa ka serbisyo nga naghimo sa tanan nga mga operasyon nga adunay mga sudlanan: pag-download sa mga imahe alang sa mga sudlanan, paglansad sa mga sudlanan, pagproseso sa mga hangyo sa API. Sukad sa bersyon 1.11, ang Docker nabahin sa daghang mga bahin nga nag-interact sa usag usa: containerd, aron pagdumala sa tibuok nga siklo sa kinabuhi sa mga sudlanan (paggahin sa disk space, pag-download sa mga hulagway, networking, paglansad, pag-instalar ug pagmonitor sa kahimtang sa mga sudlanan) ug runC , container runtimes, base sa paggamit sa cgroups ug uban pang feature sa Linux kernel. Ang serbisyo sa docker mismo nagpabilin, apan karon nagsilbi lamang kini sa pagproseso sa mga hangyo sa API nga gisibya sa containerd.

Docker ug tanan, tanan, tanan

Pag-instalar ug pag-ayo

Ang akong paborito nga paagi sa pag-install sa docker mao ang docker-machine, nga, dugang sa direkta nga pag-install ug pag-configure sa docker sa mga hilit nga server (lakip ang lainlaing mga panganod), gitugotan ka nga magtrabaho kauban ang mga file system sa hilit nga mga server, ug mahimo usab nga magpadagan sa lainlaing mga mando.

Bisan pa, sukad sa 2018, ang proyekto halos wala’y nahimo, mao nga among i-install kini sa naandan nga paagi alang sa kadaghanan nga mga pag-apod-apod sa Linux - pinaagi sa pagdugang usa ka repositoryo ug pag-install sa kinahanglan nga mga pakete.

Kini nga pamaagi gigamit usab alang sa awtomatikong pag-install, pananglitan, gamit ang Ansible o uban pang parehas nga mga sistema, apan dili nako kini tagdon sa kini nga artikulo.

Ang pag-install himuon sa Centos 7, mogamit ako usa ka virtual nga makina ingon usa ka server, aron ma-install, pagdagan lang ang mga mando sa ubos:

# 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

Human sa pag-instalar, kinahanglan nimo nga sugdan ang serbisyo, ibutang kini sa autoload:

# systemctl enable docker
# systemctl start docker
# firewall-cmd --zone=public --add-port=2377/tcp --permanent

Dugang pa, makahimo ka og usa ka grupo sa docker, kansang mga tiggamit makahimo sa pagtrabaho uban sa docker nga walay sudo, pag-set up sa pag-log, pag-enable sa pag-access sa API gikan sa gawas, ayaw kalimti ang pag-ayo sa firewall (ang tanan nga dili gitugotan mao ang gidili sa mga panig-ingnan sa ibabaw ug sa ubos - Gilaktawan ko kini alang sa kayano ug paghanduraw), apan dili nako hisgotan ang dugang nga detalye dinhi.

Ubang mga bahin

Dugang pa sa ibabaw nga docker machine, adunay usab usa ka docker registry, usa ka himan alang sa pagtipig sa mga hulagway alang sa mga sudlanan, ingon man usab sa docker compose - usa ka himan alang sa pag-automate sa pagdeploy sa mga aplikasyon sa mga sudlanan, ang YAML nga mga file gigamit sa pagtukod ug pag-configure sa mga sudlanan ug uban pang mga butang nga may kalabutan (pananglitan, mga network, padayon nga sistema sa file alang sa pagtipig sa datos).

Mahimo usab kini gamiton sa pag-organisar sa mga pipeline alang sa CICD. Ang laing makapaikag nga bahin nagtrabaho sa cluster mode, ang gitawag nga swarm mode (sa wala pa ang bersyon 1.12 kini nailhan nga docker swarm), nga nagtugot kanimo sa pag-assemble sa usa ka imprastraktura gikan sa daghang mga server aron sa pagpadagan sa mga sudlanan. Adunay suporta alang sa usa ka virtual nga network sa ibabaw sa tanan nga mga server, adunay usa ka built-in nga load balancer, ingon man suporta alang sa mga sekreto sa mga sudlanan.

Ang mga file sa YAML gikan sa docker compose mahimong magamit alang sa ingon nga mga kumpol nga adunay gagmay nga mga pagbag-o, hingpit nga awtomatiko ang pagpadayon sa gagmay ug medium nga mga kumpol alang sa lainlaing mga katuyoan. Alang sa dagkong mga pungpong, mas maayo ang Kubernetes tungod kay ang gasto sa pagmentinar sa swarm mode mahimong mas motimbang kaysa sa mga Kubernetes. Dugang pa sa runC, isip usa ka palibot sa pagpatuman alang sa mga sudlanan, mahimo nimong i-install, pananglitan Kata nga mga sudlanan

Nagtrabaho kauban ang Docker

Pagkahuman sa pag-install ug pag-configure, sulayan namon nga magtukod usa ka cluster diin among i-deploy ang GitLab ug Docker Registry alang sa development team. Isip mga server, mogamit ko og tulo ka virtual machines, diin dugangan nako nga i-deploy ang GlusterFS nga gipang-apod-apod nga FS, gamiton nako kini isip docker volumes storage, pananglitan, sa pagpadagan sa fail-safe nga bersyon sa docker registry. Panguna nga mga sangkap nga pagdagan: Docker Registry, Postgresql, Redis, GitLab nga adunay suporta alang sa GitLab Runner sa ibabaw sa Swarm. Ang Postgresql ilunsad uban ang clustering Stolon, mao nga dili nimo kinahanglan nga gamiton ang GlusterFS sa pagtipig sa datos sa Postgresql. Ang nahabilin nga kritikal nga datos itago sa GlusterFS.

Aron ma-deploy ang GlusterFS sa tanan nga mga server (gitawag sila nga node1, node2, node3), kinahanglan nimo nga i-install ang mga pakete, pagpagana sa firewall, paghimo sa kinahanglan nga mga direktoryo:

# 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

Pagkahuman sa pag-instalar, ang pagtrabaho sa pag-configure sa GlusterFS kinahanglan ipadayon gikan sa usa ka node, pananglitan 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

Unya kinahanglan nimo nga i-mount ang resulta nga gidaghanon (ang mando kinahanglan nga ipadagan sa tanan nga mga server):

# mount /srv/docker

Ang swarm mode gi-configure sa usa sa mga server, nga mahimong Lider, ang uban kinahanglan nga moapil sa cluster, mao nga ang resulta sa pagpadagan sa command sa unang server kinahanglan nga kopyahon ug ipatuman sa uban.

Inisyal nga cluster setup, akong gipadagan ang command sa 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

Kopyaha ang resulta sa ikaduhang sugo, ipatuman sa node2 ug node3:

# docker swarm join --token SWMTKN-x-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxx xx.xx.xx.xx:2377
This node joined a swarm as a manager.

Nakompleto niini ang pasiuna nga pag-configure sa mga server, magsugod kita sa pag-configure sa mga serbisyo, ang mga mando nga ipatuman ilunsad gikan sa node1, gawas kung gitakda.

Una sa tanan, maghimo kita og mga network alang sa mga sudlanan:

# 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

Pagkahuman gimarkahan namon ang mga server, kinahanglan kini aron mabugkos ang pipila nga mga serbisyo sa mga 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

Sunod, naghimo kami og mga direktoryo alang sa pagtipig sa etcd data, ang KV storage nga gikinahanglan ni Traefik ug Stolon. Susama sa Postgresql, kini mga sudlanan nga gigapos sa mga server, mao nga gipatuman namon kini nga mando sa tanan nga mga server:

# mkdir -p /srv/etcd

Sunod, paghimo usa ka file aron ma-configure ang etcd ug ipadapat kini:

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

Pagkataudtaod, among gisusi nga ang etcd cluster mitaas:

# 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

Paghimo og mga direktoryo alang sa Postgresql, ipatuman ang sugo sa tanang mga server:

# mkdir -p /srv/pgsql

Sunod, paghimo usa ka file aron ma-configure ang 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

Naghimo kami og mga sekreto, i-apply ang 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

Paglabay sa pipila ka panahon (tan-awa ang output sa command serbisyo sa docker lsnga ang tanan nga mga serbisyo nabanhaw) magsugod sa Postgresql cluster:

# 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

Pagsusi sa kaandam sa Postgresql cluster:

# 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

Gi-configure namo ang traefik aron maablihan ang access sa mga sudlanan gikan sa gawas:

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

Gisugdan namon ang Redis Cluster, tungod niini naghimo kami usa ka direktoryo sa pagtipig sa tanan nga mga 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

Idugang ang Docker Registry:

06registry.yml

version: '3.7'

services:
  registry:
    image: registry:2.6
    networks:
      - traefik
    volumes:
      - registry_data:/var/lib/registry
    deploy:
      replicas: 1
      placement:
        constraints: [node.role == manager]
      restart_policy:
        condition: on-failure
      labels:
        - traefik.enable=true
        - traefik.http.routers.registry.rule=Host(`registry.example.com`)
        - traefik.http.services.registry.loadbalancer.server.port=5000
        - traefik.docker.network=traefik

volumes:
  registry_data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: "/srv/docker/registry"

networks:
  traefik:
    external: true

# mkdir /srv/docker/registry
# docker stack deploy --compose-file 06registry.yml registry

Ug sa katapusan - 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

Ang katapusang kahimtang sa cluster ug mga serbisyo:

# 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

Unsa pa ang mahimo nga mapauswag? Siguruha nga i-configure ang Traefik aron magtrabaho sa mga sulud sa https, idugang ang tls encryption alang sa Postgresql ug Redis. Apan sa kinatibuk-an, mahimo na nimo kini ihatag sa mga developers isip PoC. Atong tan-awon karon ang mga alternatibo sa Docker.

podman

Laing medyo ilado nga makina alang sa pagpadagan sa mga sudlanan nga gi-grupo sa mga pod (mga pod, mga grupo sa mga sudlanan nga gi-deploy). Dili sama sa Docker, wala kini magkinahanglan og bisan unsang serbisyo sa pagpadagan sa mga sudlanan, ang tanan nga trabaho gihimo pinaagi sa librarya sa libpod. Gisulat usab sa Go, nanginahanglan usa ka runtime nga nagsunod sa OCI aron makadagan ang mga sulud sama sa runC.

Docker ug tanan, tanan, tanan

Ang pagtrabaho kauban ang Podman sa kinatibuk-an susama sa Docker, hangtod nga mahimo nimo kini sama niini (giangkon sa kadaghanan nga nakasulay niini, lakip ang tagsulat niini nga artikulo):

$ alias docker=podman

ug makapadayon ka sa pagtrabaho. Sa kinatibuk-an, ang sitwasyon sa Podman makaiikag kaayo, tungod kay kung ang unang mga bersyon sa Kubernetes nagtrabaho uban sa Docker, unya sukad sa mga 2015, human sa pag-standardize sa container world (OCI - Open Container Initiative) ug pagbahin sa Docker ngadto sa containerd ug runC, usa ka alternatibo sa Ang Docker gipalambo aron modagan sa Kubernetes: CRI-O. Ang Podman niining bahina usa ka alternatibo sa Docker, nga gitukod sa mga prinsipyo sa Kubernetes, lakip ang container grouping, apan ang nag-unang tumong sa proyekto mao ang pagpadagan sa Docker-style nga mga sudlanan nga walay dugang nga mga serbisyo. Alang sa klaro nga mga hinungdan, wala’y swarm mode, tungod kay klaro nga giingon sa mga developer nga kung kinahanglan nimo ang usa ka kumpol, kuhaa ang Kubernetes.

Pag-instalar

Aron ma-install sa Centos 7, i-activate lang ang Extras repository, ug dayon i-install ang tanan gamit ang command:

# yum -y install podman

Ubang mga bahin

Ang Podman makahimo og mga yunit alang sa systemd, sa ingon masulbad ang problema sa pagsugod sa mga sudlanan human sa pag-reboot sa server. Dugang pa, ang systemd gideklarar nga molihok sa husto ingon pid 1 sa sulud. Aron magtukod og mga sudlanan, adunay usa ka bulag nga himan sa buildah, adunay usab mga himan sa ikatulo nga partido - mga analogue sa docker-compose, nga nagmugna usab sa mga file sa pag-configure nga katugma sa Kubernetes, mao nga ang pagbalhin gikan sa Podman hangtod sa Kubernetes ingon kadali kutob sa mahimo.

Nagtrabaho sa Podman

Tungod kay walay swarm mode (kini kinahanglan nga mobalhin sa Kubernetes kung gikinahanglan ang usa ka cluster), ato kining tigumon sa lain nga mga sudlanan.

I-install ang podman-compose:

# yum -y install python3-pip
# pip3 install podman-compose

Ang resulta nga config file alang sa podman gamay nga lahi, sama pananglit kinahanglan namon nga ibalhin ang usa ka separado nga seksyon sa volume direkta sa seksyon sa mga serbisyo.

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

Resulta sa trabaho:

# 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

Atong tan-awon kung unsa ang mahimo niini alang sa systemd ug kubernetes, alang niini kinahanglan naton mahibal-an ang ngalan o id sa pod:

# podman pod ls
POD ID         NAME   STATUS    CREATED          # OF CONTAINERS   INFRA ID
71fc2b2a5c63   root   Running   11 minutes ago   3                 db40ab8bf84b

Mga 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: {}

systemd:

# podman generate systemd 71fc2b2a5c63
# pod-71fc2b2a5c6346f0c1c86a2dc45dbe78fa192ea02aac001eb8347ccb8c043c26.service
# autogenerated by Podman 1.6.4
# Thu Jul 29 15:23:28 EDT 2020

[Unit]
Description=Podman pod-71fc2b2a5c6346f0c1c86a2dc45dbe78fa192ea02aac001eb8347ccb8c043c26.service
Documentation=man:podman-generate-systemd(1)
Requires=container-781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3.service container-da53da946c01449f500aa5296d9ea6376f751948b17ca164df438b7df6607864.service
Before=container-781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3.service container-da53da946c01449f500aa5296d9ea6376f751948b17ca164df438b7df6607864.service

[Service]
Restart=on-failure
ExecStart=/usr/bin/podman start db40ab8bf84bf35141159c26cb6e256b889c7a98c0418eee3c4aa683c14fccaa
ExecStop=/usr/bin/podman stop -t 10 db40ab8bf84bf35141159c26cb6e256b889c7a98c0418eee3c4aa683c14fccaa
KillMode=none
Type=forking
PIDFile=/var/run/containers/storage/overlay-containers/db40ab8bf84bf35141159c26cb6e256b889c7a98c0418eee3c4aa683c14fccaa/userdata/conmon.pid

[Install]
WantedBy=multi-user.target
# container-da53da946c01449f500aa5296d9ea6376f751948b17ca164df438b7df6607864.service
# autogenerated by Podman 1.6.4
# Thu Jul 29 15:23:28 EDT 2020

[Unit]
Description=Podman container-da53da946c01449f500aa5296d9ea6376f751948b17ca164df438b7df6607864.service
Documentation=man:podman-generate-systemd(1)
RefuseManualStart=yes
RefuseManualStop=yes
BindsTo=pod-71fc2b2a5c6346f0c1c86a2dc45dbe78fa192ea02aac001eb8347ccb8c043c26.service
After=pod-71fc2b2a5c6346f0c1c86a2dc45dbe78fa192ea02aac001eb8347ccb8c043c26.service

[Service]
Restart=on-failure
ExecStart=/usr/bin/podman start da53da946c01449f500aa5296d9ea6376f751948b17ca164df438b7df6607864
ExecStop=/usr/bin/podman stop -t 10 da53da946c01449f500aa5296d9ea6376f751948b17ca164df438b7df6607864
KillMode=none
Type=forking
PIDFile=/var/run/containers/storage/overlay-containers/da53da946c01449f500aa5296d9ea6376f751948b17ca164df438b7df6607864/userdata/conmon.pid

[Install]
WantedBy=multi-user.target
# container-781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3.service
# autogenerated by Podman 1.6.4
# Thu Jul 29 15:23:28 EDT 2020

[Unit]
Description=Podman container-781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3.service
Documentation=man:podman-generate-systemd(1)
RefuseManualStart=yes
RefuseManualStop=yes
BindsTo=pod-71fc2b2a5c6346f0c1c86a2dc45dbe78fa192ea02aac001eb8347ccb8c043c26.service
After=pod-71fc2b2a5c6346f0c1c86a2dc45dbe78fa192ea02aac001eb8347ccb8c043c26.service

[Service]
Restart=on-failure
ExecStart=/usr/bin/podman start 781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3
ExecStop=/usr/bin/podman stop -t 10 781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3
KillMode=none
Type=forking
PIDFile=/var/run/containers/storage/overlay-containers/781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3/userdata/conmon.pid

[Install]
WantedBy=multi-user.target

Ikasubo, gawas sa paglansad sa mga sudlanan, ang namugna nga yunit alang sa systemd wala’y mahimo (pananglitan, paglimpyo sa mga daan nga sudlanan kung ang ingon nga serbisyo gi-restart), mao nga kinahanglan nimo nga idugang ang ingon nga mga butang sa imong kaugalingon.

Sa prinsipyo, igo na ang Podman aron sulayan kung unsa ang mga sudlanan, pagbalhin sa daan nga mga pag-configure alang sa docker-compose, ug dayon moadto sa Kubernetes, kung kinahanglan, sa usa ka kumpol, o makakuha usa ka dali nga magamit nga alternatibo sa Docker.

rkt

Ang proyekto miadto sa archive mga unom ka bulan ang milabay tungod sa kamatuoran nga gipalit kini sa RedHat, mao nga dili nako kini hisgotan sa mas detalyado. Sa kinatibuk-an, nagbilin kini usa ka maayo kaayo nga impresyon, apan kung itandi sa Docker, ug labi pa sa Podman, kini ingon usa ka kombinasyon. Adunay usab usa ka pag-apod-apod sa CoreOS nga gitukod sa ibabaw sa rkt (bisan kung sila adunay orihinal nga Docker), apan natapos usab kini pagkahuman sa pagpalit sa RedHat.

Flash

Dugang pa usa ka proyekto, ang tagsulat niini gusto lang nga magtukod ug magpadagan og mga sudlanan. Sa paghukom sa dokumentasyon ug code, ang tagsulat wala mosunod sa mga sumbanan, apan nakahukom lamang sa pagsulat sa iyang kaugalingong pagpatuman, nga, sa prinsipyo, iyang gibuhat.

kaplag

Ang sitwasyon sa Kubernetes makapainteres kaayo: sa usa ka bahin, uban sa Docker, mahimo ka nga mag-assemble sa usa ka cluster (sa swarm mode), diin mahimo ka nga magpadagan sa mga palibot sa produksiyon alang sa mga kliyente, ilabi na kini alang sa gagmay nga mga team (3-5 ka tawo). ), o uban ang gamay nga kinatibuk-ang karga , o ang kakulang sa tinguha nga masabtan ang mga kakuti sa pag-set up sa mga Kubernetes, lakip ang alang sa taas nga mga karga.

Ang Podman wala maghatag bug-os nga pagkaangay, apan kini adunay usa ka hinungdanon nga bentaha - pagkaangay sa Kubernetes, lakip ang dugang nga mga himan (buildah ug uban pa). Busa, ako moduol sa pagpili sa usa ka himan alang sa trabaho sama sa mosunod: alang sa gagmay nga mga team, o uban sa usa ka limitado nga budget - Docker (nga adunay usa ka posible nga swarm mode), alang sa pagpalambo sa akong kaugalingon sa usa ka personal nga localhost - Podman kauban, ug alang sa tanan. - Kubernetes.

Dili ko sigurado nga ang sitwasyon sa Docker dili mausab sa umaabot, human sa tanan, sila mga pioneer, ug hinay-hinay usab nga nag-standard sa matag lakang, apan ang Podman, uban ang tanan nga mga kakulangan niini (nagtrabaho lamang sa Linux, walay clustering. , asembliya ug uban pang mga aksyon ang mga desisyon sa ikatulo nga partido) mas klaro ang umaabot, busa gidapit nako ang tanan nga hisgutan kini nga mga nahibal-an sa mga komento.

PS Sa Agosto 3 gilusad namo ang "Docker nga kurso sa videodiin makakat-on ka og dugang mahitungod sa iyang trabaho. Atong analisahon ang tanan nga mga himan niini: gikan sa mga batakang abstraction hangtod sa mga parameter sa network, mga nuances sa pagtrabaho sa lainlaing mga operating system ug mga programming language. Masinati nimo ang teknolohiya ug masabtan kung diin ug kung giunsa ang labing kaayo nga paggamit sa Docker. Magpaambit usab kami sa labing maayo nga praktis nga mga kaso.

Pre-order nga gasto sa wala pa buhian: 5000 nga mga rubles. Ang programa nga "Docker Video Course" makita sa panid sa kurso.

Source: www.habr.com

Idugang sa usa ka comment