Русский
Русский
English
Статистика
Реклама

Podman

Docker и все, все, все

31.07.2020 04:19:23 | Автор: admin

TL;DR: обзорная статья-руководство по сравнению сред для запуска приложений в контейнерах. Будут рассмотрены возможности Docker и других схожих систем.



Немножко истории, откуда все взялось

История


Первым общеизвестным способом изоляции приложения является chroot. Одноименный системный вызов обеспечивает изменение корневого каталога таким образом обеспечивая доступ программе, его вызвавшей, доступ только к файлам внутри этого каталога. Но если программе внутри дать права суперпользователя, потенциально она может убежать из chroot и получить доступ к основной операционной системе. Также кроме смены корневого каталога не ограничиваются другие ресурсы (оперативная память, процессор), а также доступ к сети.


Следующий способ запуск полноценной операционной системы внутри контейнера, за счет механизмов ядра операционной системы. В различных операционных системах этот способ называют по-разному, но суть одна и та же запуск нескольких независимых операционных систем, каждая из которых работает с тем же ядром, на котором работает и основная операционная система. Сюда относятся FreeBSD Jails, Solaris Zones, OpenVZ и LXC для Linux. Обеспечивается изоляция не только по дисковому пространству, но и другим ресурсам, в частности каждый контейнер может иметь ограничения по процессорному времени, оперативной памяти, полосе пропускания сети. По сравнению с chroot выйти из контейнера сложнее, поскольку суперпользователь в контейнере обладает доступом только к начинке контейнера, однако из-за необходимости поддерживать операционную систему внутри контейнера в актуальном состоянии и использования старых версий ядер (актуально для Linux, в меньшей мере FreeBSD) есть ненулевая вероятность пробития системы изоляции ядра и получения доступа к основной операционной системе.


Вместо запуска полноценной операционной системы в контейнере (с системой инициализации, пакетным менеджером и т.п.) можно запускать сразу же приложения, главное обеспечить приложениям такую возможность (наличие необходимых библиотек и прочих файлов). Эта идея и послужила основой для контейнерной виртуализации приложений, наиболее ярким и общеизвестным представителем которой является Docker. По сравнению с предыдущими системами более гибкие механизмы изоляции совместно с встроенной поддержкой виртуальных сетей между контейнерами и с отслеживанием состояния приложения внутри контейнера дали в результате возможность построения единой целостной среды из большого числа физических серверов для запуска контейнеров без необходимости ручного управления ресурсами.


Docker


Docker это наиболее известное ПО для контейнеризации приложений. Написан на языке Go, использует штатные возможности ядра Linux cgroups, namespaces, capabilities и т.п., а также файловые системы Aufs и другие подобные для экономии дискового пространства.



Источник: wikimedia


Архитектура


До версии 1.11 Docker работал в виде единого сервиса, который осуществлял все операции с контейнерами: скачивание образов для контейнеров, запуск контейнеров, обработку запросов по API. Начиная с версии 1.11 Docker разбили на несколько частей, взаимодействующих между собой: containerd, для обработки всего жизненного цикла контейнеров (выделение дискового пространства, скачивание образов, работа с сетью, запуск, установка и наблюдение за состоянием контейнеров) и runC, среды исполнения контейнеров, основанной на использовании cgroups и прочих возможностей ядра Linux. Сам сервис docker остался, но теперь он служит только для обработки запросов по API, транслируемых в containerd.



Установка и настройка


Моим любимым способом установки docker является docker-machine, который кроме непосредственно установки и настройки docker на удаленные сервера (включая различные облака) дает возможность работы с файловыми системами удаленных серверов, а также может производить запуск различных команд.


Однако с 2018 года проект почти не развивается, поэтому установку будем производить штатным для большинства дистрибутивов Linux способом добавлением репозитория и установкой необходимых пакетов.


Также этот способ применяется и при автоматизированной установке, например с помощью Ansible или других подобных систем, но в этой статье я его рассматривать не буду.


Установка будет производиться на Centos 7, в качестве сервера я буду использовать виртуальную машину, для установки достаточно выполнить команды ниже:


# 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

После установки надо запустить сервис, поставить его в автозагрузку:


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

Дополнительно можно создать группу docker, пользователи которой смогут работать с docker без sudo, настроить журналирование, включить доступ к API извне, но тут я более подробно не буду останавливаться.


Другие возможности


Кроме вышеназванной docker machine еще есть docker registry, средство для хранения образов для контейнеров, а также docker compose средство для автоматизации развертывания приложений в контейнерах, используются файлы YAML для сборки и настройки контейнеров и прочих связанных вещей (например сети, постоянные файловые системы для хранения данных).


Также с его помощью можно организовать конвейеры для CI\CD. Другая интересная возможность работа в кластерном режиме, так называемый swarm mode (до версии 1.12 был известен как docker swarm), позволяющая собрать из нескольких серверов единую инфраструктуру для запуска контейнеров. Имеется поддержка виртуальной сети поверх всех серверов, есть наличие встроенного балансировщика нагрузки, а также поддержка секретов для контейнеров.


Файлы YAML от docker compose с небольшими изменениями могут быть использованы для таких кластеров, полностью автоматизируя обслуживание малых и средних кластеров для различных целей. Для больших кластеров предпочтительнее использовать Kubernetes, поскольку затраты на обслуживание swarm mode могут превзойти таковые с Kubernetes. Кроме runC в качестве среды исполнения контейнеров можно установить например Kata containers


Работа с Docker


После установки и настройки попробуем собрать кластер, в котором развернем GitLab и Docker Registry для команды разработчиков. В качестве серверов я буду использовать три виртуальные машины, на которых дополнительно разверну распределенную ФС GlusterFS, ее я буду использовать в качестве хранилища docker volumes, например для запуска отказоустройчивой версии docker registry. Ключевые компоненты для запуска: Docker Registry, Postgresql, Redis, GitLab с поддержкой GitLab Runner поверх Swarm. Postgresql будем запускать с кластеризацией Stolon, поэтому для хранения данных Postgresql не надо использовать GlusterFS. Остальные критические данные будут храниться на GlusterFS.


Для разворачивания GlusterFS на всех серверах (они именуются node1, node2, node3) нужно установить пакеты, разрешить работу firewall, создать нужные каталоги:


# 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

После установки работу по настройке GlusterFS надо продолжать с одного узла, например 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

Затем надо смонтировать полученный volume (команду нужно выполнить на всех серверах):


# mount /srv/docker

Настройка swarm mode производится на одном из серверов, который будет Leader, остальные должны будут присоединяться к кластеру, поэтому результат выполнения команды на первом сервере надо будет скопировать и выполнить на остальных.


Первичная настройка кластера, команду запускаю на node1:


# docker swarm initSwarm 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:2377To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.# docker swarm join-token manager

Копируем результат второй команды, выполняем на node2 и node3:


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

На этом предварительная настройка серверов окончена, приступаем к настройке сервисов, команды для выполнения будут запускаться с node1, если не указано иначе.


Первым делом создадим сети для контейнеров:


# 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

Затем помечаем сервера, это нужно для привязки некоторых сервисов к серверам:


# docker node update --label-add nodename=node1 node1# docker node update --label-add nodename=node2 node2# docker node update --label-add nodename=node3 node3

Далее создаем каталоги для хранения данных etcd, KV-хранилища, которое нужно для Traefik и Stolon. Аналогично Postgresql это будут привязанные к серверам контейнеры, поэтому эту команду выполняем на всех серверах:


# mkdir -p /srv/etcd

Далее создаем файл для настройки etcd и применяем его:


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

Через некоторое время проверяем, что поднялся etcd кластер:


# docker exec $(docker ps | awk '/etcd/ {print $1}')  etcdctl member listade526d28b1f92f7: name=etcd1 peerURLs=http://etcd1:2380 clientURLs=http://etcd1:2379 isLeader=falsebd388e7810915853: name=etcd3 peerURLs=http://etcd3:2380 clientURLs=http://etcd3:2379 isLeader=falsed282ac2ce600c1ce: name=etcd2 peerURLs=http://etcd2:2380 clientURLs=http://etcd2:2379 isLeader=true# docker exec $(docker ps | awk '/etcd/ {print $1}')  etcdctl cluster-healthmember ade526d28b1f92f7 is healthy: got healthy result from http://etcd1:2379member bd388e7810915853 is healthy: got healthy result from http://etcd3:2379member d282ac2ce600c1ce is healthy: got healthy result from http://etcd2:2379cluster is healthy

Создаем каталоги для Postgresql, команду выполняем на всех серверах:


# mkdir -p /srv/pgsql

Далее создаем файл для настройки 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: rollbackvolumes:  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

Генерируем секреты, применяем файл:


# </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

Спустя некоторое время (смотрим вывод команды docker service ls, что поднялись все сервисы) инициализируем кластер 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

Проверяем готовность кластера 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      LEADER26baa11d    false74e98768    falsea8cb002b    true=== Active proxies ===ID4d2338269f562f3bb0c79ff1=== Keepers ===UID     HEALTHY PG LISTENADDRESS    PG HEALTHY  PG WANTEDGENERATION PG CURRENTGENERATIONpgkeeper1   true    pgkeeper1:5432         true     2           2pgkeeper2   true    pgkeeper2:5432          true            2                   2pgkeeper3   true    pgkeeper3:5432          true            3                   3=== Cluster Info ===Master Keeper: pgkeeper3===== Keepers/DB tree =====pgkeeper3 (master)pgkeeper2pgkeeper1

Настраиваем traefik для открытия доступа к контейнерам извне:


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=traefiknetworks:  traefik:    external: true

# docker stack deploy --compose-file 03traefik.yml traefik

Запускаем Redis Cluster, для этого создаем на всех узлах каталог для хранения:


# 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: anyvolumes:  redis:    driver: local    driver_opts:      type: 'none'      o: 'bind'      device: "/srv/redis"networks:  redis:    external: true

# docker stack deploy --compose-file 05redis.yml redis

Добавляем Docker 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=traefikvolumes:  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

Ну и наконец 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'        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'] = "noreply@example.com"        gitlab_rails['smtp_password'] = "xxxxxxxxx"        gitlab_rails['smtp_domain'] = "example.com"        gitlab_rails['gitlab_email_from'] = 'noreply@example.com'        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 == managervolumes:  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

Итоговое состояние кластера и сервисов:


# docker service lsID                  NAME                   MODE                REPLICAS            IMAGE                          PORTSlef9n3m92buq        etcd_etcd1             replicated          1/1                 quay.io/coreos/etcd:latestij6uyyo792x5        etcd_etcd2             replicated          1/1                 quay.io/coreos/etcd:latestfqttqpjgp6pp        etcd_etcd3             replicated          1/1                 quay.io/coreos/etcd:latesthq5iyga28w33        gitlab_gitlab          replicated          1/1                 gitlab/gitlab-ce:latest        *:22222->22/tcpdt7s6vs0q4qc        gitlab_gitlab-runner   replicated          1/1                 gitlab/gitlab-runner:latestk7uoezno0h9n        pgsql_pgkeeper1        replicated          1/1                 sorintlab/stolon:master-pg10cnrwul4r4nse        pgsql_pgkeeper2        replicated          1/1                 sorintlab/stolon:master-pg10frflfnpty7tr        pgsql_pgkeeper3        replicated          1/1                 sorintlab/stolon:master-pg10x7pqqchi52kq        pgsql_pgsentinel       replicated          3/3                 sorintlab/stolon:master-pg10mwu2wl8fti4r        pgsql_postgresql       replicated          3/3                 sorintlab/stolon:master-pg109hkbe2vksbzb        redis_redis-master     global              3/3                 bitnami/redis:latest           *:6379->6379/tcpl88zn8cla7dc        redis_redis-replica    replicated          3/3                 bitnami/redis:latest           *:30003->6379/tcp1utp309xfmsy        redis_redis-sentinel   global              3/3                 bitnami/redis:latest           *:30002->16379/tcpoteb824ylhyp        registry_registry      replicated          1/1                 registry:2.6qovrah8nzzu8        traefik_traefik        replicated          3/3                 traefik:latest                 *:80->80/tcp, *:443->443/tcp

Что еще можно улучшить? Обязательно настроить в Traefik работу контейнеров по https, добавить шифрование tls для Postgresql и Redis. Но в целом уже можно отдавать разработчикам в качестве PoC. Посмотрим теперь альтернативы Docker.


Podman


Еще один достаточно известный engine для запуска контейнеров, сгруппированные по подам (pods, группы контейнеров, развернутых совместно). В отличие от Docker не требует какого-либо сервиса для запуска контейнеров, вся работа производится через библиотеку libpod. Также написан на Go, нуждается в OCI-совместимом runtime для запуска контейнеров, например runC.



Работа с Podman в целом напоминает таковую для Docker, вплоть до того, что можно сделать так (заявлено у многих попробовавших, в том числи и автором этой статьи):


$ alias docker=podman

и можно продолжать работать. В целом ситуация с Podman весьма интересная, ведь если ранние версии Kubernetes работали с Docker, то примерно с 2015 года, после стандартизации мира контейнеров (OCI Open Container Initiative) и выделения из Docker на containerd и runC, развивается альтернатива Docker для запуска в Kubernetes: CRI-O. Podman в этом плане является альтернативой Docker, построенной по принципам Kubernetes, в том числе и по группировке контейнеров, но основная цель существования проекта запуск контейнеров в стиле Docker без дополнительных сервисов. По понятным причинам нет наличия swarm mode, так как разработчики явно говорят о том, что если надо кластер берите Kubernetes.


Установка


Для установки в Centos 7 достаточно активировать репозиторий Extras, после чего установить все командой:


# yum -y install podman

Другие возможности


Podman может генерировать юниты для systemd, таким образом решая задачу запуска контейнеров после перезагрузки сервера. Дополнительно заявлена корректная работа systemd в качестве pid 1 в контейнере. Для сборки контейнеров идет отдельный инструмент buildah, есть также сторонние инструменты аналоги docker-compose, генерирующий в том числе конфигурационные файлы, совместимые с Kubernetes, так что переход с Podman на Kubernetes упрощен насколько это возможно.


Работа с Podman


Поскольку нет swarm mode (предполагается переход на Kubernetes, если надо кластер) собирать будем отдельными контейнерами.


Устанавливаем podman-compose:


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

Результирующий конфигурационный файл для podman немного отличается, так к примеру пришлось перенести отдельную секцию volumes напрямую в секцию с сервисами.


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:      - gitlabnetworks:  gitlab:

# podman-compose -f gitlab-runner.yml -d up

Результат работы:


# podman psCONTAINER ID  IMAGE                                  COMMAND               CREATED             STATUS                 PORTS                                      NAMESda53da946c01  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_1781c0103c94a  docker.io/gitlab/gitlab-ce:latest      /assets/wrapper       About a minute ago  Up About a minute ago  0.0.0.0:22222->22/tcp, 0.0.0.0:80->80/tcp  root_gitlab_1

Давайте посмотрим, что он сгенерирует для systemd и kubernetes, для этого надо узнать имя или id пода:


# podman pod lsPOD ID         NAME   STATUS    CREATED          # OF CONTAINERS   INFRA ID71fc2b2a5c63   root   Running   11 minutes ago   3                 db40ab8bf84b

Kubernetes:
# podman generate kube 71fc2b2a5c63# Generation of Kubernetes YAML is still under development!## Save the output of this file and use kubectl create -f to import# it into Kubernetes.## Created with podman-1.6.4apiVersion: v1kind: Podmetadata:  creationTimestamp: "2020-07-29T19:22:40Z"  labels:    app: root  name: rootspec:  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-confstatus: {}

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.serviceDocumentation=man:podman-generate-systemd(1)Requires=container-781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3.service container-da53da946c01449f500aa5296d9ea6376f751948b17ca164df438b7df6607864.serviceBefore=container-781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3.service container-da53da946c01449f500aa5296d9ea6376f751948b17ca164df438b7df6607864.service[Service]Restart=on-failureExecStart=/usr/bin/podman start db40ab8bf84bf35141159c26cb6e256b889c7a98c0418eee3c4aa683c14fccaaExecStop=/usr/bin/podman stop -t 10 db40ab8bf84bf35141159c26cb6e256b889c7a98c0418eee3c4aa683c14fccaaKillMode=noneType=forkingPIDFile=/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.serviceDocumentation=man:podman-generate-systemd(1)RefuseManualStart=yesRefuseManualStop=yesBindsTo=pod-71fc2b2a5c6346f0c1c86a2dc45dbe78fa192ea02aac001eb8347ccb8c043c26.serviceAfter=pod-71fc2b2a5c6346f0c1c86a2dc45dbe78fa192ea02aac001eb8347ccb8c043c26.service[Service]Restart=on-failureExecStart=/usr/bin/podman start da53da946c01449f500aa5296d9ea6376f751948b17ca164df438b7df6607864ExecStop=/usr/bin/podman stop -t 10 da53da946c01449f500aa5296d9ea6376f751948b17ca164df438b7df6607864KillMode=noneType=forkingPIDFile=/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.serviceDocumentation=man:podman-generate-systemd(1)RefuseManualStart=yesRefuseManualStop=yesBindsTo=pod-71fc2b2a5c6346f0c1c86a2dc45dbe78fa192ea02aac001eb8347ccb8c043c26.serviceAfter=pod-71fc2b2a5c6346f0c1c86a2dc45dbe78fa192ea02aac001eb8347ccb8c043c26.service[Service]Restart=on-failureExecStart=/usr/bin/podman start 781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3ExecStop=/usr/bin/podman stop -t 10 781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3KillMode=noneType=forkingPIDFile=/var/run/containers/storage/overlay-containers/781c0103c94aaa113c17c58d05ddabf8df4bf39707b664abcf17ed2ceff467d3/userdata/conmon.pid[Install]WantedBy=multi-user.target

К сожалению кроме запуска контейнеров сгенерированный юнит для systemd больше ничего не делает (например зачистку старых контейнеров при перезапуске такого сервиса), поэтому такие вещи придется дописывать самостоятельно.


В принципе Podman достаточно для того, чтобы попробовать, что такое контейнеры, перенести старые конфигурации для docker-compose, после чего уйти в сторону Kubernetes, если надо на кластер, либо получить более простую в работе альтернативу Docker.


rkt


Проект ушел в архив примерно полгода назад из-за того, что его купил RedHat, поэтому не буду останавливаться на нем детальнее. В целом он оставлял весьма неплохое впечатление, однако по сравнению с Docker и тем более с Podman выглядит комбайном. Существовал также дистрибутив CoreOS, построенный на основе rkt (хотя у них изначально был Docker), однако его поддержка также окончилась после покупки RedHat.


Plash


Еще один проект, автор которого хотел просто собирать и запускать контейнеры. Судя по документации и коду автор не следовал стандартам, а просто решил написать свою реализацию, что в принципе и сделал.


Выводы


Ситуация при наличии Kubernetes складывается весьма интересная: с одной стороны с Docker можно собрать кластер (в swarm mode), с которым даже можно запускать продуктовые среды для клиентов, это особенно актуально для небольших команд (3-5 человек), либо при небольшой общей нагрузке, или же отсутствию желания разбираться в тонкостях настройки Kubernetes в том числе и для высоких нагрузок.


Podman не обеспечивает полной совместимости, но у него есть одно важное преимущество совместимость с Kubernetes, в том числе и по дополнительным инструментам (buildah и прочие). Поэтому к выбору инструмента для работы я буду подходить так: для малых команд, либо при ограниченном бюджете Docker (с возможным swarm mode), для разработки для себя на личном localhost Podman сотоварищи, а всем остальным Kubernetes.


Я не уверен, что ситуация с Docker не поменяется в будущем, все-таки они являются пионерами, а также шаг за шагом потихоньку стандартизируются, но у Podman при всех его недостатках (работа только на Linux, нету кластеризации, сборка и прочие действия сторонними решениями) будущее более ясное, поэтому я приглашаю всех желающих обсудить данные выводы в комментариях.


P.S. 3 августа запускаем Видеокурс по Docker, где можно будет подробнее узнать о его работе. Мы разберем все его инструменты: от основных абстракций до параметров сети, нюансов работы с различными ОС и языками программирования. Вы познакомитесь с технологией и поймете, где и как лучше использовать Docker. Также поделимся best practice кейсами.


Стоимость предзаказа до релиза: 5000 р. С программой Видеокурса по Docker можно ознакомиться на странице курса.

Подробнее..

Шпаргалка по Ansible k8s, практичный учебник по awk, а также 4 причины использовать Jamstack при веб-разработке

24.09.2020 14:19:46 | Автор: admin


Традиционно короткий дайджест полезных материалов, найденных нами в сети за последние две недели.

Начни новое:



Качай:


  • Шпаргалка по Ansible k8s
    Ansible k8s это специальный модуль для управления объектами Kubernetes из плейбуков Ansible. Как объединить Ansible и Kubernetes при автоматизации облака? Ответ: использовать модуль Ansible k8s, чтобы управлять объектами Kubernetes прямо из плейбуков. И поможет в этом наша шпаргалка, которая содержит полезные советы и сведения по ключевым командам этого модуля.
  • Шпаргалка по тестированию приложений Quarkus


  • Книжка-раскраска Контейнерные супергерои
    Децентрализованная команда опенсорсных контейнерных супергероев в лице Podman, CRI-O, Buildah, Skopeo и OpenShift спасает Землю от атаки астероидов, развертывая над планетой защитный экран.



Почитать на досуге:



Мероприятия:


  • 30 сентября, jconf.dev
    Бесплатная виртуальная Java-конференция прямо у вас на экране. Четыре технотрека с экспертами по Java и облаку, 28 углубленных сессий и два потрясающих основных доклада.
  • 13-14 октября, AnsibleFest
    Выступления, демонстрации, практические занятия и все это в онлайне. Отличная возможность виртуально пообщаться с девелоперами, админами и ЛПР-ами, которые успешно справляются с вызовами перемен с помощью опенсорсных технологий ИТ-автоматизации.

По-русски:


Мы продолжаем серию пятничных вебинаров про нативный опыт использования Red Hat OpenShift Container Platform и Kubernetes. Регистрируйтесь и приходите:

Император Оператор: Операторы в OpenShift и Kubernetes
Упс, вебинар прошел, но есть запись.

OpenShift-специфичные волшебные вещи для сборки и развертывания приложений
Вебинар кончился, но остался в истории ловите запись.

Подробнее..

Разработка и тестирование Ansible-ролей с использованием Molecule и Podman

17.09.2020 10:15:44 | Автор: admin
Одно из основных преимуществ Red Hat Ansible Automation Platform заключается в том, что ее язык описания автоматизаций читабелен не только для пары-тройки гуру, но и почти для всех, кто имеет отношение к ИТ. Поэтому вносить свой вклад в автоматизацию могут любые специалисты, что сильно облегчает организацию межкомандного взаимодействия и внедрение автоматизации на уровне корпоративной культуры.



Однако, когда делом занимается такая масса народа, очень важно все тщательно тестировать. При разработке Ansible-контента, вроде плейбуков, ролей или коллекций, мы очень рекомендуем предварительно проверять все в тестовой среде, прежде чем выкатывать в продакшн. Цель такого тестирования удостовериться, что все работает как надо, чтобы избежать неприятных сюрпризов на боевых системах.

Тестирование автоматизационного контента штука довольно сложная, поскольку для этого надо развертывать специальную инфраструктуру тестирования и настраивать условия тестирования, чтобы обеспечить релевантность самих тестов. Molecule это комплексная инфраструктура тестирования, которая помогает разрабатывать и тестировать роли Ansible, чтобы вы могли сосредоточиться на разработке автоматизаций и не отвлекаться на управление инфраструктурой тестирования.

Вот как это декларируется в документации проекта:

Molecule призван помочь в разработке и тестировании ролей Ansible, и способствует внедрению подхода, результатом которого являются комплексно проработанные роли, которые хорошо написаны, просты в понимании и поддержке.

Molecule позволяет протестировать роль на множестве целевых инстансов, чтобы проверить ее в различных комбинациях операционных систем и сред виртуализации. Без него для каждой из таких комбинаций пришлось бы создавать и поддерживать отдельную среду тестирования, настраивать подключение к тестовым инстансам и откатывать их в исходное состояние перед каждым тестированием. Molecule же делает все это за вас, причем автоматизированным и воспроизводимым образом.

В этой серии из двух частей мы покажем, как применять Molecule при разработке и тестировании ролей Ansible. В первой части рассмотрим установку и настройку Molecule, во второй разработку ролей с его помощью.

Если роль является частью коллекции, используйте этот подход для разработки и юнит-тестирования роли. В следующей статье мы покажем, как применять Molecule для выполнения интегрированных тестов в коллекции.

Molecule использует драйверы для предоставления целевых инстансов на базе различных технологий, включая Linux-контейнеры, виртуальные машины и облачных провайдеров. По умолчанию он идет с тремя предустановленными драйверами: Docker и Podman для контейнеров, а также драйвером Delegated для создания кастомных интеграций. Драйверы для других провайдеров предоставляются сообществом разработки проекта.

В этом посте мы будем использовать драйвер Podman для разработки и тестирования новой роли с использованием Linux-контейнеров. Podman это легковесный контейнерный движок для Linux, ему не нужен работающий демон и он обеспечивает запуск rootless-контейнеров, что хорошо для безопасности.

Используя Molecule с драйвером Podman, мы с нуля разработаем и протестируем новую роль Ansible, которая развертывает веб-приложение на базе веб-сервера Apache и должна работать на Red Hat Enterprise Linux (RHEL) 8 или Ubuntu 20.04.

Мы разбираем типовой сценарий, когда роль должна работать на различных версиях операционной системы. Используя Podman и Linux-контейнеры, мы можем создать несколько инстансов, чтобы протестировать роль на разных версиях ОС. Благодаря своей легковесности, контейнеры позволяют быстро итерировать функциональность роли прямо по ходу разработки. Использование контейнеров для тестирования ролей применимо в данной ситуации, поскольку роль конфигурирует только запущенные инстансы Linux. Для тестирования на других целевых системах или облачных инфраструктурах можно использовать драйвер delegated или другие драйверы, предоставляемые сообществом.

Что нам понадобится


Для примеров из этой статьи нужна физическая или виртуальная машина Linux с установленными Python 3 и Podman (мы используем RHEL 8.2). Также Podman должен был сконфигурирован для запуска rootless-контейнеров. Установка Podman выходит за рамки этой статьи, для получения соответствующей информации см. официальную документацию. Установка Podman на RHEL 8 также описывается в документации по контейнерам RHEL 8.

Приступаем


Molecule выполнен в виде Python-пакета и, соответственно, устанавливается через pip. Первым шагом мы создаем выделенное Python-окружение и устанавливаем в него наш Molecule:

$ mkdir molecule-blog$ cd molecule-blog$ python3 -m venv molecule-venv$ source molecule-venv/bin/activate(molecule-venv) $ pip install "molecule[lint]"

Обратите внимание, что мы устанавливаем Molecule с опцией lint, чтобы pip также поставил инструменты yamllint и ansible-lint, которые позволят нам использовать Molecule для статического анализа кода роли на предмет соответствия стандартам кодирования Ansible.

Установка скачивает все необходимые зависимости из интернета, включая Ansible. Теперь смотрим что мы установили:

$ molecule --versionmolecule 3.0.4   ansible==2.9.10 python==3.6

Что ж, пора использовать команду molecule, чтобы инициализировать новую роль Ansible.

Инициализируем новую роль Ansible


Вообще говоря, при разработке новой роли Ansible, она инициализируется командой ansible-galaxy role init, но мы будем использовать вместо этого команду molecule. При этом мы получим ту же структуру роли, что и с командой ansible-galaxy, а также базовую заготовку кода для запуска тестов Molecule.

По умолчанию Molecule использует для выполнения тестов драйвер Docker. Поскольку мы хотим использовать вместо него podman, то при инициализации роли командой molecule надо указать соответствующий драйвер с помощью опции --driver-name=podman.

Переключаемся обратно в каталог molecule-blog и инициализируем новую роль mywebapp следующей командой:

$ molecule init role mywebapp --driver-name=podman--> Initializing new role mywebapp...Initialized role in /home/ricardo/molecule-blog/mywebapp successfully.

Molecule создает структуру нашей роли в папке mywebapp. Переключаемся в эту папку и смотрим, что там:

$ cd mywebapp$ tree. defaults    main.yml files handlers    main.yml meta    main.yml molecule    default        converge.yml        INSTALL.rst        molecule.yml        verify.yml README.md tasks    main.yml templates tests    inventory    test.yml vars     main.yml 10 directories, 12 files

Molecule складывает свои конфигурационные файлы в подкаталог molecule. При инициализации новой роли здесь появляется всего один сценарий, который называется default. Позднее сюда можно добавить свои сценарии для тестирования различных условий. В этой статье мы будем использовать только сценарий default.

Проверим базовую конфигурацию в файле molecule/default/molecule.yml:

$ cat molecule/default/molecule.yml ---dependency:  name: galaxydriver:  name: podmanplatforms:  - name: instance    image: docker.io/pycontribs/centos:7    pre_build_image: trueprovisioner:  name: ansibleverifier:  name: ansible

Как мы и просили, в этом файле указано, что для тестов применяется драйвер Podman. Здесь же задается платформа по умолчанию для тестового инстанса, через контейнерный образ docker.io/pycontribs/centos:7, который мы потом поменяем.

В отличие Molecule v2, Molecule v3 не задает линтер по умолчанию. Поэтому откроем конфигурационный файл molecule/default/molecule.yml и допишем в конце конфигурацию lint:

$ vi molecule/default/molecule.yml...verifier:  name: ansiblelint: |  set -e  yamllint .  ansible-lint .

Сохраним и закроем файл, и запустим команду molecule lint из корневой папки нашего проекта, чтобы прогнать линтер по всему проекту:

$ molecule lint

На выходе получаем несколько ошибок, поскольку в файле meta/main.yml нет ряда требуемых значений. Исправим это: отредактируем файл meta/main.yml, добавив author, company, license, platforms и удалив пустую строку в конце. Для краткости обойдемся без комментариев, и тогда наш meta/main.yaml будет выглядеть так:

$ vi meta/main.ymlgalaxy_info:  author: Ricardo Gerardi  description: Mywebapp role deploys a sample web app   company: Red Hat    license: MIT    min_ansible_version: 2.9   platforms:  - name: rhel    versions:    - 8   - name: ubuntu    versions:    - 20.04   galaxy_tags: [] dependencies: []

Еще раз прогоним по проекту линтер и убедимся, что ошибок больше нет.

$ molecule lint--> Test matrix     default     dependency     lint    --> Scenario: 'default'--> Action: 'dependency'Skipping, missing the requirements file.Skipping, missing the requirements file.--> Scenario: 'default'--> Action: 'lint'--> Executing: set -eyamllint .ansible-lint . 

Итак, наша роль инициализирована и базовая конфигурация molecule тоже на месте. Теперь создадим тестовый инстанс.

Создаем тестовый инстанс


По умолчанию Molecule задает только один инстанс, которые называется instance и создается из образа Centos:7. Наша роль, если помните, должна работать на RHEL 8 и Ubuntu 20.04. Кроме того, поскольку она запускает веб-сервер Apache в качестве системной службы, нам нужен контейнерный образ с включенным systemd.

У Red Hat есть официальный Universal Base Image для RHEL 8 с включенным systemd:

registry.access.redhat.com/ubi8/ubi-init

Для Ubuntu нет официального образа с systemd, поэтому мы воспользуемся образом, который поддерживается силами Джефа Джирлинга (Jeff Geerling) из сообщества Ansible:

geerlingguy/docker-ubuntu2004-ansible

Чтобы получить инстансы с systemd, подправим конфигурационный файл molecule/default/molecule.yml, убрав из него инстанс centos:7 и добавив два новых инстанса:

$ vi molecule/default/molecule.yml---dependency:  name: galaxydriver:  name: podmanplatforms:  - name: rhel8    image: registry.access.redhat.com/ubi8/ubi-init    tmpfs:      - /run      - /tmp    volumes:      - /sys/fs/cgroup:/sys/fs/cgroup:ro    capabilities:      - SYS_ADMIN    command: "/usr/sbin/init"    pre_build_image: true  - name: ubuntu    image: geerlingguy/docker-ubuntu2004-ansible    tmpfs:      - /run      - /tmp    volumes:      - /sys/fs/cgroup:/sys/fs/cgroup:ro    capabilities:      - SYS_ADMIN    command: "/lib/systemd/systemd"    pre_build_image: trueprovisioner:  name: ansibleverifier:  name: ansiblelint: |  set -e  yamllint .  ansible-lint .

С помощью этих параметров мы монтируем для каждого инстанса временную файловую систему /run и /tmp, а также том cgroup. Кроме того, мы включаем функцию SYS_ADMIN, необходимую для запуска контейнеров с Systemd.

Если делать все по уму и выполнять этот пример на машине RHEL 8 с включенным SELinux, то еще надо установить в true логический параметр container_manage_cgroup, чтобы контейнеры могли запускать Systemd, (подробнее см. документацию RHEL 8):

sudo setsebool -P container_manage_cgroup 1

Для инициализации этих инстансов Molecule использует Ansible Playbook. Изменим и добавим параметры инициализации, модифицировав словарь provisioner в конфигурационном файле molecule/default/molecule.yml.

Он принимает те же самые опции конфигурации, что прописаны в конфигурационном файле ansible.cfg. Например, обновим конфигурацию провайдера (provisioner), добавив секцию defaults. Установим интерпретатор Python в auto_silent, чтобы деактивировать предупреждения. Включим callback-плагины profile_tasks, timer и yaml, чтобы профайлерская информация включалась в вывод Playbook. И наконец, добавим секцию ssh_connection и отключим SSH pipelining, поскольку он не работает с Podman:

provisioner:  name: ansible  config_options:    defaults:      interpreter_python: auto_silent      callback_whitelist: profile_tasks, timer, yaml    ssh_connection:      pipelining: false

Сохраним этот файл и создадим инстанс командой molecule create из корневого каталога нашей роли:

$ molecule create

Molecule выполнит инициализационный плейбук и создаст оба наших инстанса. Проверим их командой molecule list:

$ molecule listInstance Name    Driver Name    Provisioner Name    Scenario Name    Created    Converged---------------  -------------  ------------------  ---------------  ---------  -----------rhel8            podman         ansible             default          true       falseubuntu           podman         ansible             default          true       false

Также проверим, что оба контейнера запущены в Podman:

$ podman psCONTAINER ID  IMAGE                                                   COMMAND               CREATED             STATUS                 PORTS  NAMES2e2f14eaa37b  docker.io/geerlingguy/docker-ubuntu2004-ansible:latest  /lib/systemd/syst...  About a minute ago  Up About a minute ago         ubuntu2ce0a0ea8692  registry.access.redhat.com/ubi8/ubi-init:latest         /usr/sbin/init        About a minute ago  Up About a minute ago         rhel8

При разработке роли Molecule использует запущенные инстансы для ее тестирования. Если тест проваливается или какая-то ошибка приводит к необратимым изменениям, из-за которых все надо начинать сначала, вы можете в любое время убить эти инстансы командой molecule destroy и создать их заново командной molecule create.

Заключение


Если вам не терпится и хочется поглубже копнуть тему разработки и тестирования ролей, или тему Ansible-автоматизации, то рекомендуем следующие ресурсы:

Подробнее..

Что будет после Docker

12.06.2021 08:11:13 | Автор: admin

Такой мыслью я задался, обдумывая и перечитывая свою статью про Docker для одного внутреннего корпблога. Этот материал -- продолжение этой крайне, крайне субъективной мысли, оформленное во что-то, что может понять и оценить не только я и моя мама-редактор. Это, конечно, не избавляет текст от моих предубеждений, впечатлений от тех или иных технологий, восторга юного, впечатлительного ума от всего нового и блестящего. Но главное, что кто-нибудь да сможет извлечь из неё что-то своё, описать своё мнение, или сделать свой новый инструментарий для контейнеризации.

Кроме того, отмечу, что у меня нет особых претензий к Docker. Просто хорошая прорывная технология, которая стала стандартом индустрии разработки и администрирования. Как bash или Python у сисадминов. Я постараюсь описывать недостатки докера только при сравнении с другими технологиями, и всё.

Почему вообще должно появиться что-то после Docker?

Окей, насчёт запрета на недостатки Docker я соврал, они будут. Но только пара пунктов -- остальные можете почитать в посте "Исповедь docker хейтера", с которыми я, в принципе, согласен. Так вот.

Отсутствие развития. Я не вижу, чтобы в Docker появлялось что-то принципиально новое в последние пару лет. Может, это из-за не очень понятной финансовой модели и вкладывания ресурсов в не то, чтобы перспективный Swarm. Вы сможете вспомнить хайлайты из последних ченжлогов докера? То-то же.

Спорные и местами даже предвзятые решения разработчиков. Дело в том, что Docker в современном дистрибутиве Linux это система в системе, которая активно перетягивает на себя одеяло остальных инструментов: правила фаерволла в iptables (firewalld? Не, не слышали!), инициализация и жизненный цикл приложений (другими словами, докер стремится стать systemd для контейнеров, то есть это сегодня нечто systemd-like в дистрибутиве Linux, где уже есть systemd? шта?), работа от непривелегированных пользователей (и я не про системную группу docker, через которую можно лезть в чужие контейнеры и хостовую систему вообще!), не очень удобный механизм сборки (Dockerfile, конечно, хорошо, но вы попробуйте построить замысловатый пайплайн с пробросом хостовых томов, например), в общем, список наберётся.

Так что же будет после Docker?

Во-первых, будет новый докер. Перефразирую слова из песни одной музыкальной группы: вначале был докер, в конце будет докер, всё повторяется снова, природа сурова. Вполне вероятно, что докер эволюционирует, что его команда и сообщество решат архитектурные и технические болячки, прикрутят сотню крутых фич, сохраняя при этом дистанцию от кубера, выкинут Docker Swarm и всё станет хорошо. Но это, разумеется, не точно. Честно говоря, я сомневаюсь в таком сценарии.

Во-вторых, будет иной докер. Пример сегодня живёт хорошей жизнью и вполне себе развивается -- Podman. С одной стороны, он создан по образу и подобию Docker: CLI мимикрирует под Docker CLI, есть режим эмуляции Docker API для совместимости с docker-compose, технологии под капотом примерно те же, да и написан он тоже на Go.
Но дальше идут различия: например, Podman построен на стандартах OCI, на которые ориентируются остальные инструменты, вроде Harbor container registry. Когда как Docker позволяет от себе отклоняться от стандартов в различных мелочах, просто потому что докер появился до этих стандартов и имеет право.
Это расхождение в стандарте и реализации иногда порождает проблемы. Так, например, я при работе с Podman столкнулся с тем, что Sonatype Nexus отказывается принимать подмановские docker-образы, и надо было использовать особый параметр, чтобы подман собирал образы с конкретно докеровским форматом, а не стандартом OCI. Так что стандарты -- круто, своя имплементация -- не всегда практично.

В-третьих, будет антидокер. Нет, это не аллюзия на антикафе, только где вы платите деньги за время, которое проводите в контейнере. Да, речь о Kubernetes, который расширяет Docker кучей абстракций, концепций, API и всего причитающегося.

В конце-концов, может, я преувеличил касательно Docker как bash современной разработки, и после Docker будет что-то совершенно иное. Может, это будет Serverless?

Каким мог бы быть совершенный Docker?

Для меня критерии совершенного инструмента для разработки и управления контейнерами следующие:

  • Он должен вбирать в себя всё хорошее, что уже есть в Docker, а именно -- отличные REST API и CLI.

  • В нём должны быть результаты уроков, извлечённые из горького опыта Docker, то есть большинство из того, что сделано в Podman.

  • Он должен быть ещё более тесно интегрирован с дистрибутивом Linux. Не так тесно, как systemd-nspawn, который вообще неотделим от systemd, но всё же.

  • Он должен выполнять только определённый круг задач: собирать контейнеры, запускать контейнеры, и ещё всякое по мелочи. Не надо кластеризации, не надо поддерживать сложные сценарии со множеством сетей или томов, максимум -- пробрасывать папки в хостовую файловую систему. Ну и какой-то функционал Docker Compose тоже не помешает.

  • Каким-то образом решить архитектурный косяк с dangling images. Типа, серьёзно, 2021-й год, а мне приходится в кронтабы плейбуков или systemd-таймеры вписывать задачу на docker image prune -f! Это должен делать или сам сервис, то есть самостоятельно маскировать проблему, или это надо решить на уровне дизайна системы работы с образами.

  • Удобная расширяемость через плагины! К сожалению, язык Go не имеет возможности писать расширяемые через классические плагины системы, как умеет Python или Java. Как фанат Kotlin, я нахожу расширяемость через плагины или скрипты (я имею ввиду Kotlin Script) очень клёвой.

У меня на этом всё.

С-спасибо за внимание, в-вы отличная публика (c)

Подробнее..

Пишем Hello World на WebAssembly, шпаргалка по Linux-команде sed, а также 15 самых востребованных ИТ-сертификатов года

08.04.2021 18:23:51 | Автор: admin

И вновь мы приготовили для вас много инсайтов, мероприятий, книжек и шпаргалок. Оставайтесь с нами станьте частью DevNation!

Узнать новое:

Скачать:

  • Шпаргалка по Linux-команде sed
    SED (Stream EDitor) это потоковый текстовый редактор, который построчно обрабатывает входной поток (файл).

  • Бесплатный Developer Sandbox for OpenShift
    Это ваш личный OpenShift в облаке, всего за пару минут и без какой бы то ни было инсталляции. Среда создана специально для разработчиков и включает в себя Helm-диаграммы, builder-образы Red Hat, инструменты сборки s2i, также CodeReady Workspaces, облачную IDE с веб-интерфейсом.

Почитать на досуге:

Мероприятия:

  • Виртуальный Red Hat Summit 2021, 27-28 апреля
    Бесплатная онлайн-конференция Red Hat Summit это отличный способ узнать последние новости ИТ-индустрии, задать свои вопросы техническим экспертам, услышать истории успеха непосредственно от заказчиков Red Hat и увидеть, как открытый код генерирует инновации в корпоративном секторе

Подробнее..

Поэтапное преобразование виртуализованных нагрузок в контейнеры OpenShift

18.03.2021 14:16:42 | Автор: admin

Унаследованные приложения, как правило, имеют монолитную архитектуру и запускаются на одной или нескольких виртуальных машинах. Некоторые из таких систем легче поддаются модернизации, поскольку в мире контейнеров для них есть неплохие аналоги (EAP, Spring Boot и т.д.). Однако большие классические приложения на .Net, работающие под IIS на Windows-сервере, модернизировать гораздо сложнее, тем более за одну итерацию. Но благодаря OpenShift Virtualization такие ВМ-нагрузки можно импортировать в OpenShift как есть и затем контейнеризировать их поэтапно.

В OpenShift виртуальные машины являются привилегированными гражданами и имеют ровно те же возможности, что и podы, включая обращение к другим объектам и предоставление доступа к себе через конечные точки служб (service endpoints). Поэтому выполнив первичный перенос ВМ-приложения в OpenShift, его затем можно поэтапно модернизировать, а заодно и расширять функционал.

Стратегия миграции Shift and Modernize

Чтобы показать, как это делается, мы для примера возьмем приложение .Net, работающее под IIS на виртуалке Windows Server, импортируем его в OpenShift Virtualization, а затем поэтапно контейнеризуем все его логические слои. Обратите внимание, что стратегия shift and modernize подходит и для других связок операционная системасвязующее ПО.

Этап 1. Импорт ВМ в OpenShift Virtualization

Импорт ВМ в OpenShift возможен несколькими способами. Для виртуальных машин VMware можно использоватьвстроенный инструментарий миграции, который позволяет подключиться к экземпляру VSphere и напрямую импортировать эти виртуалки в OpenShift Virtualization. Для других платформ виртуализации, включая Hyper-V и Xen, можно использовать virt-v2v, чтобы конвертировать образ ВМ в формат, поддерживаемый OpenShift Virtualization, а затем импортировать этот образ, используя методы описанные здесь (EN).

Виртуальная машина запускается с помощью Yaml-конфигурации, базовый вариант которой можно найтиздесь. Этот Yaml-файл содержит определение ВМ, а также объектов service и route, плюс, некоторые функциональные конфигурации для более эффективной работы Windows-ВМ на платформе OpenShift Virtualization.

Нас интересует следующее секция:

 features: acpi: {} apic: {} hyperv: reenlightenment: {} ipi: {} synic: {} synictimer: {} spinlocks: spinlocks: 8191 reset: {} relaxed: {} vpindex: {} runtime: {} tlbflush: {} frequencies: {} vapic: {} evmcs: {} # do not use evmcs if testing with nested virt

После применения этого yaml, мы получаем доступ к графическому интерфейсу Windows UI через VNC Console, которую нам дает OpenShift Virtualization.

Кроме того, теперь у нас есть доступ к приложению через exposed route.

Этап 2. Контейнеризация UI приложения

Не всегда можно мигрировать всё сразу, особенно в случае больших приложений. Например, этому могут препятствовать зависимости от библиотек, которые есть в классическом .NET, но отсутствуют в .Net Core. В этом случае код приложения придется доработать.

И поскольку это можно делать поэтапно, мы начнем с веб-интерфейса и после того, как переведем UI-слой на .Net Core, упакуем его в контейнерный образ для OpenShift. Этот новый UI-pod будет потреблять API, которые предоставляются старым сайтом, работающем под IIS на виртуальной машине.

Приведенный ниже Dockerfile компилирует ваш код .Net Core и создает runtime-образ. Это также можно сделать через сборки S2I.

# https://hub.docker.com/_/microsoft-dotnet-coreFROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS buildWORKDIR /source# copy csproj and restore as distinct layersCOPY ./source .RUN dotnet restore# copy and publish app and librariesCOPY . .RUN dotnet publish -c release -o /app --no-restore# final stage/imageFROM mcr.microsoft.com/dotnet/core/aspnet:3.1WORKDIR /appCOPY --from=build /app .ENTRYPOINT ["dotnet", "ClientListUI.dll"]

Для сборки и отправки этого образа в реестр можно использовать podman. Затем остается только развернуть этот отвечающий за веб-интерфейс pod вместе с виртуальной машиной приложения.

Этап 3. Контейнеризация API

Вслед за UI-слоем мигрируем на .Net Core слой API и развернем его в виде отдельного podа. После чего на исходной виртуалке остается только база данных SQL Server. Соответствующим образом поправим сервис ВМ в части описания доступа:

kind: ServiceapiVersion: v1metadata: name: stage3-win2019-db-vm namespace: stage3 labels: kubevirt.io: virt-launcher kubevirt.io/domain: stage3-win2019-iis-vmspec:  ports: - protocol: TCP port: 1433 targetPort: 1433 selector: kubevirt.io: virt-launcher kubevirt.io/domain: stage3-win2019-iis-vm

Итак, теперь UI-pod нашего приложения вызывает API через service URL нашего API-podа, а тот в свою очередь использует service URL нашей виртуальной машины, чтобы делать запросы к базе данных.

Этап 4. Контейнеризация БД

Да, вы правильно поняли: миграция экземпляра MS SQL в контейнер RHEL. Лет пять назад такое и в голову бы никому не пришло, но сегодня это вполне рабочий вариант и подробнее узнать о том, как настроить и запустить MS SQL в контейнере, можно узнать здесь (EN).

После того, SQL-pod будет готов, остается настроить port forwarding, чтобы можно было работать с БД через MS SQL Management Studio или Azure Data Studio:

 oc get pod | grep sql | grep Runningsql2019-1-1-gp29h 1/1 Running 0 39h oc port-forward sql2019-1-1-gp29h 1433:1433Forwarding from 127.0.0.1:1433 -> 1433Forwarding from [::1]:1433 -> 1433Handling connection for 1433

Теперь можно переносить БД из экземпляра MS SQL на Windows-виртуалке в контейнер SQL Server. После чего, необходимо изменить строку подключения для API-podа приложения и указать в ней pod, где теперь живет ваш MS SQL.

Всё, приложение полностью, на 100% контейнеризовано, и виртуальную машину которую, мы перенесли на первом этапе, можно навсегда отключить.

Заключение

Поэтапная миграция ВМ-нагрузки по методу shift and modernize позволяет снизить технический долг, минимизировать любого рода регрессии, которые могут возникнуть входе этого процесса, ну и попутно расширить функционал приложения в рамках проводимой при такой миграции доработки кода.

Подробнее..

Бесплатный онлайн-курс Основы Ansible, шпаргалка по GNU Screen, запись Red Hat Summit и многое другое

06.05.2021 14:05:14 | Автор: admin

Мы знаем, как провести эти праздники максимально полезно: собрали для вас много новых инсайтов, записей важных вебинаров, книжек и шпаргалок. Прокачивайте скилы, читайте, смотрите, думайте, применяйте на практике! Станьте частью DevNation!

Узнать новое:

Скачать:

Что еще интересного:

Мероприятия:

Вебинары:

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru