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

Администрирование linux-систем

Консольный менеджер сертификатов для JKSPCKS12

05.02.2021 14:16:53 | Автор: admin

Привет Хабр!

С момента популяризации https, работа с сертификатами теперь есть практически в каждом проекте.

habr-certificatehabr-certificate

Сертификаты, которые любой может сгенерировать сам;
Сертификаты которые выдает местный СА в компании, доверие к которому есть только внутри компании;
Бесплатный публичный let's encrypt
Платный сертификат от крупных центров авторизации с дополнительными услугами, типа проверки компании.

Сертификаты для tls/ssl, сертификаты для авторизации, сертификаты для two-say-tls/ssl - даже в пределах одного небольшого проекта с десятком микросервисов и несколькими тестовыми окружениями - сертификатов набирается уйма.

При работе с множеством сертификатов, их удобно хранить не отдельными файлами, а складывать в хранилища (keystore). Самые популярные keystore форматы на сегодня - JKS (java keystore, который считается legacy с выходом 9-й джавы) и PKCS12. Последний вышел уже около 20 лет назад, и несмотря на некоторую критику, является одним из самых надежных, открытых и популярных форматов, который в скором будущем должен уже полностью вытеснить JKS.

Я много работал в проектах, где основным языком разработки был java, поэтому при работе с keystore основной инструмент для меня это консольная утилита keytool, которая поставляется с JDK. И для большинства популярных действий у меня конечно есть микро-шпаргалка:

Посмотреть список сертификатов:

keytool -list -v -keystore "файл.jks" -storepass "пароль"|grep -P '(Alias name:|Entry type:|Serial number:|Owner:|Valid from:)'

Скопировать сертификат из одного keystore в другой keystore:

keytool -importkeystore -srckeystore "откуда.jks" -srcstorepass "пароль" -destkeystore "куда.jks" -deststorepass "пароль" -srcalias "имя сертификата" [ -destalias "новое имя" ]

Импортировать сертификат в keystore из PEM файла:

keytool -import -file "откуда.pem" -keystore "куда.jks" -storepass "пароль" -noprompt -alias "имя_сертификата"

Экспортировать сертификат из keystore в файл:

keytool -exportcert -v -alias "alias" -keystore "keystore.jks" -storepass "storepassword" -rfc -file "exportedcert.cer"

Но однажды мне пришлось поработать в проекте, где сертификатов оказалось мягко говоря много. Плюс несколько сотен виртуалок и контейнеров, где все сертификаты обновлялись вручную. Перед тем? как подойти к вопросу автоматизации, было необходимо все это разобрать и причесать. Но долгое время руки просто не доходили - с одной стороны были вещи более приоритетные а сертификаты в общем напрягали нечасто. С другой стороны, опыта разгребания такого объема у меня раньше не было, и навскидку казалось, что в лоб задача решается слишком уныло и кропотливо, браться за нее по своей инициативе не хотелось - задача чисто техническая, никакие менеджеры и представители бизнеса такое перед нашей командой не ставили. Но где-то в подсознании желание все это перебрать и привести в порядок крутилось. Изредка я почитывал статьи, просматривал сертификат эксплореры, но все они были под графическую оболочку Windows, а политика безопасности не позволяла ставить в компании неодобренный софт на десктопы.

Возможно, я бы собрался силой воли, помучился бы недельку, сделал бы все стандартными однострочниками+notepad+excel, но тут внезапно у меня случился больничный отпуск, а когда температура меня попустила, а на работу еще можно было не выходить, я случайно вспомнил, что считаю себя спецом по bash.

И пусть я не хватаю лавры автора PIUPIU), но тем не менее встречайте:

Консольный двух-панельный keystore менеджер на Linux shell.

Сперва я написал рабочий вариант на bash, но в какой-то момент подумал и переписал все башизмы в пользу POSIX совместимости. Код стал выглядеть более громоздко, зато скрипт проверенно работает в bash/ksh/dash без проблем.
Если я что-то пропустил - напишите в комментариях, ну или форкайте на здоровье ;)

Также используется sed и grep, по поводу последнего - я не очень уверен, насколько POSIX-совместимо grep -P. Но если что, там несложно переписать на sed.

Некоторое сожаление: привычка работы с java вынудила меня всю работу с хранилищами выполнять именно через keystore, который должен быть доступен в PATH (а может быть стоило разобраться и сделать все через openssl?).

Но давайте к делу. Что умеет менеджер вкратце можно наглядно увидеть на скриншотах.

В одно-панельном режиме:

В двух-панельном режиме:

Для поклонников панельных менеджеров (NC, VC, MC, FAR и др), функциональные клавиши и навигация должны быть интуитивно понятны.

Весьма важным плюсом я считаю, что jks_mgr.sh - это просто шелл скрипт, одним файлом размером 20 килобайт (update: уже 30+ кб) (update2: уже 35+ кб).

Никаких обсфукаций, код максимально простой - проверить на отсутствие закладок может в принципе любой джуниор - то есть такой скрипт можно использовать в любом проекте, не нарушая никаких требований по безопасности, требований по лицензионности, лоялен к производительности, установка не нужна - лишь бы на целевой машине был доступен шелл, keytool, sed и grep.

Что было самое интересное во время разработки:

Автоматическая подстройка панелей под высоту/ширину экрана.

Так как экран у меня перерисовывается почти с каждым нажатием, то менять ширину экрана (например если сидеть через графический ssh клиент) можно в произвольное время - после первого же нажатия любой клавиши экран перерисуется и все адаптируется. Пару вечеров ушло на опции отображения/скрытия столбцов - нужно было высчитать и отладить подстройку для одно-панельного и двух-панельного режима, плюс заголовки и текст считается разными формулами. Вот кусочек для определения насколько надо обрезать Certificate Alias, если экран слишком узкий и затем пример вывода заголовка:

WindowWidth="$(tput cols)"if [ -n "$RFILE" ]; then # two-panel    used=24    [ -n "$SHOW_TYPE" ] && used=$(( $used+34 ))    localWidth=$(( ( $WindowWidth - $used ) / 2 - 1 ))    if [ $localWidth -ne $aliasWidth ]; then        aliasWidth=$localWidth        [ $aliasWidth -lt 1 ] && aliasWidth=1        clear    fi..................................headerWidth=$(( $aliasWidth + 5 ))[ -n "$SHOW_TYPE" ] && headerWidth=$(( $headerWidth + 17 ))printf " store: ${blue}%-$(( $headerWidth ))s${rst}" "$LFILE"printf "| store: ${blue}%-$(( $headerWidth -1 ))s${rst}\n" "$RFILE"printf " %-10s" "Valid to"[ -n "$SHOW_TYPE" ] && printf " %-16s" "Storetype"printf " %-${aliasWidth}s |" "Alias"printf " %-10s" "Valid to"[ -n "$SHOW_TYPE" ] && printf " %-16s" "Storetype"printf " %-${aliasWidth}s\n" "Alias"

Определение нажатия функциональных клавиш.

Некоторые специальные keypress могут иметь длину до 4 символов, поэтому просто через read было сделать непросто - он не позволяет вариативно менять длину читаемой строки, но после поиска в гугле и экспериментов c read в bash/dash, это выглядит так:

# Special keypress could take up to 4 charactersread -rsN1 keypressif [ "$keypress" == "$escape_char" ]; then    read -sn1 -t 0.01 k1    read -sn1 -t 0.01 k2    read -sn1 -t 0.01 k3    read -sn1 -t 0.01 k4    keypress=${k1}${k2}${k3}${k4}    unset k1 k2 k3 k4fi

Теперь можно сравнивать $keypress с комбинациями типа '[A' (стрелка вверх), '[B' (стрелка вниз), '[13~' (F3) и так далее. Я не совсем уверен, что мой вариант будет работать везде идеально - поэтому на всякий случай почти все хоткеи продублированы обычными буквами.

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

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

Я догадываюсь, что можно заметно ускорить навигацию - производительность в git-bash ужасна - мне быстрее скопировать keystore на ближайшую виртуалку, поковырять там менеджером и скопировать исправленный keystore назад. Но нужно будет переписывать много вычислений, делать независимую пагинацию для каждой панели, а на Linux все работает отлично, поэтому в текущем варианте скрипт меня устраивает и дойдут ли руки до переделки - не уверен.

В конце нужно написать какой-то умный итог и заключение ну он простой:

Хочешь получить от практики удовольствие - придумай задачу, результат которой будет полезен для тебя.

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

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

P.S. На фоне некоторых проблем с nginx, Wargaming и др., сразу хочу уточнить, что jks_mgr.sh был написан ИСКЛЮЧИТЕЛЬНО в нерабочее время на личном компьютере.

Подробнее..

Ломаем и чиним Kubernetes

05.02.2021 20:16:55 | Автор: admin

Kubernetes отличная платформа как для оркестрации контейнеров так и для всего остального. За последнее время Kubernetes ушёл далеко вперёд как по части функциональности так и по вопросам безопасности и отказоустойчивости. Архитектура Kubernetes позволяет с лёгкостью переживать сбои различного характера и всегда оставаться на плаву.

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


Итак приступим. Основной control-plane Kubernetes состоит всего из нескольких компонентов:

  • etcd - используется в качестве базы данных

  • kube-apiserver - API и сердце нашего кластера

  • kube-controller-manager - производит операции над Kubernetes-ресурсами

  • kube-scheduller - основной шедуллер

  • kubelet'ы - которые непосредственно и запускают контейнеры на хостах

Каждый из этих компонентов защищён набором TLS-сертификатов, клиентских и серверных, которые используются для аутентификации и авторизации компонентов между ссобой. Они не хранятся где-либо в базе данных Kuberentes, за исключением определенных случаев, а представлены в виде обычных файлов:

# tree /etc/kubernetes/pki//etc/kubernetes/pki/ apiserver.crt apiserver-etcd-client.crt apiserver-etcd-client.key apiserver.key apiserver-kubelet-client.crt apiserver-kubelet-client.key ca.crt ca.key CTNCA.pem etcd    ca.crt    ca.key    healthcheck-client.crt    healthcheck-client.key    peer.crt    peer.key    server.crt    server.key front-proxy-ca.crt front-proxy-ca.key front-proxy-client.crt front-proxy-client.key sa.key sa.pub

Сами компоненты описаны и запускаются на мастерах как static pods из директории /etc/kubernetes/manifests/

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

Основная схема выглядит примерно так:

(стрелочки указывают на связи клиент --> сервер)(стрелочки указывают на связи клиент --> сервер)

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


Предположим, что у нас уже есть задеплоенный кластер. Начнём с самого интересного:

rm -rf /etc/kubernetes/

На мастерах данная директория содержит:

  • Набор сертификатов и CA для etcd (в /etc/kubernetes/pki/etcd)

  • Набор сертификатов и CA для Kubernetes (в /etc/kubernetes/pki)

  • Kubeconfig для cluster-admin, kube-controller-manager, kube-scheduller и kubelet (каждый из них также имеет закодированный в base64 CA-сертификат для нашего кластера /etc/kubernetes/*.conf)

  • Набор статик-манифеств для etcd, kube-apiserver, kube-scheduller и kube-controller-manager (в /etc/kubernetes/manifests)

Чиним control-plane

Чтобы не было недоразумений, давайте также убедимся что все наши control-plane поды также остановлены:

crictl rm `crictl ps -aq`

Примечание: kubeadm по умолчанию не перезаписывает уже существующие сертификаты и кубеконфиги, для того чтобы их перевыпустить их необходимо сначала удалить вручную.

Давайте начнём с восстановления etcd, так как если у нас был кворум (3 и более мастер-нод) etcd-кластер не запустится без присутствия большинства из них.

kubeadm init phase certs etcd-ca

- сгенерит новый CA для нашего etcd-кластера. Так как все остальные сертификаты должны быть им подписанны, скопируем его вместе с приватным ключём на остальные мастер-ноды:

/etc/kubernetes/pki/etcd/ca.{key,crt}

Теперь перегенерим остальные etcd-сертификаты и static-манифесты для него на всех control-plane нодах:

kubeadm init phase certs etcd-healthcheck-clientkubeadm init phase certs etcd-peerkubeadm init phase certs etcd-serverkubeadm init phase etcd local

На этом этапе у нас уже должен подняться работоспособный etcd-кластер:

# crictl psCONTAINER ID        IMAGE               CREATED             STATE               NAME                ATTEMPT             POD IDac82b4ed5d83a       0369cf4303ffd       2 seconds ago       Running             etcd                0                   bc8b4d568751b

Теперь давайте проделаем тоже самое, но для для Kubernetes, на одной из master-нод выполним:

kubeadm init phase certs allkubeadm init phase kubeconfig allkubeadm init phase control-plane allcp -f /etc/kubernetes/admin.conf ~/.kube/config

Вышеописанные команды сгенирируют все SSL-сертификаты нашего Kubernetes-кластера.

Если вы используете kubeadm для джойна кубелетов, вам также потребуется обновить конфиг cluster-info в kube-public неймспейсе т.к. он до сих пор содержит хэш вашего старого CA.

kubeadm init phase bootstrap-token

Так как все сертификаты на других инстансах также должны быть подписаны одним CA, скопируем его на остальные control-plane ноды, и повторим вышеописанные команды на каждой из них.

/etc/kubernetes/pki/{ca,front-proxy-ca}.{key,crt}/etc/kubernetes/pki/sa.{key,pub}

Кстати, в качестве альтернативы ручного копирования сертификатов теперь вы можете использовать интерфейс Kubernetes, например следующая команда:

kubeadm init phase upload-certs --upload-certs

Зашифрует и загрузит сертификаты в Kubernetes на 2 часа, таким образом вы сможете сделать реджойн мастеров следующим образом:

kubeadm join phase control-plane-prepare all kubernetes-apiserver:6443 --control-plane --token cs0etm.ua7fbmwuf1jz946l     --discovery-token-ca-cert-hash sha256:555f6ececd4721fed0269d27a5c7f1c6d7ef4614157a18e56ed9a1fd031a3ab8 --certificate-key 385655ee0ab98d2441ba8038b4e8d03184df1806733eac131511891d1096be73kubeadm join phase control-plane-join all

Стоит заметить, что в API Kubernetes есть ещё один конфиг, который хранит CA сертификат для front-proxy client, он используется для аутентификации запросов от apiserver в вебхуках и прочих aggregation layer сервисах. К счастью kube-apiserver обновляет его автоматически.

Однако возможно вы захотите почистить его от старых сертификатов вручную:

kubectl get cm -n kube-system extension-apiserver-authentication -o yaml

В любом случае на данном этапе мы уже имеем полностью рабочий control-plane.

Чиним воркеров

Эта компанда выведет список всех нод кластера, хотя сейчас все они будут в статусе NotReady:

kubectl get node

Это потому что они по прежнему используют старые сертификаты и с ожидают запросов apiserver, подписанных старым CA. Для того чтобы это исправить мы воспользуемся kubeadm, и сделаем реджойн нод в кластер.

Когда как мастера имеют доступ к CA и могут быть присоеденены локально:

systemctl stop kubeletrm -rf /var/lib/kubelet/pki/ /etc/kubernetes/kubelet.confkubeadm init phase kubeconfig kubeletkubeadm init phase kubelet-start

То для джойна воркеров мы сгенерируем новый токен:

kubeadm token create --print-join-command

и на каждом из них выполним:

systemctl stop kubeletrm -rf /var/lib/kubelet/pki/ /etc/kubernetes/pki/ /etc/kubernetes/kubelet.conf kubeadm join phase kubelet-start kubernetes-apiserver:6443  --token cs0etm.ua7fbmwuf1jz946l     --discovery-token-ca-cert-hash sha256:555f6ececd4721fed0269d27a5c7f1c6d7ef4614157a18e56ed9a1fd031a3ab8

Внимание, удалять директорию /etc/kubernetes/pki/ на мастерах не нужно, так как она уже содержит все необходимые сертификаты.

Вышеописанная процедура переподключит все ваши kubelet'ы обратно к кластеру, при этом никак не повлияет на уже запущенные на них контейнеры. Однако если у вас в кластере много нод и вы сделаете это неодновременно, у вас может возникнуть ситуация когда controller-manager начнёт пересоздавать контейнеры с NotReady-нод и пытаться их запустить на живых нодах кластера.

Чтобы это предотвратить мы можем временно остановить controller-manager, на мастерах:

rm /etc/kubernetes/manifests/kube-controller-manager.yamlcrictl rmp `crictl ps --name kube-controller-manager -q`

Последняя команда нужна просто для того, чтобы удостовериться что под с controller-manager действительно не запущен. Как только все ноды кластера будут присоединены мы можем сгенерировать static-manifest для controller-manager обратно.

Для этого на всех мастерах выполняем:

kubeadm init phase control-plane controller-manager

Учтите что делать это нужно на этапе когда вы уже сгенерировали join token, в противном случае операция подключения зависнет на попытке прочитать токен из cluser-info.

В случае если kubelet настроен на получение сертификата подписанного вашим CA (опция serverTLSBootstrap: true), вам также потребуется заново подтвердить csr от ваших kubelet'ов:

kubectl get csrkubectl certificate approve <csr>

Чиним ServiceAccounts

Есть ещё один момент. Так как мы потеряли /etc/kubernetes/pki/sa.key - это тот самый ключ которм были подписаны jwt-токены для всех наших ServiceAccounts, то мы должны пересоздать токены для каждого из них.

Сделать это можно достаточно просто, удалив все секреты типа kubernetes.io/service-account-token:

kubectl get secret --all-namespaces | awk '/kubernetes.io\/service-account-token/ { print "kubectl delete secret -n " $1 " " $2}' | sh -s

После чего kube-controller-manager автоматически сгенерирует новые, подписанные новым ключём.

К сожалению далеко не все микросервисы умеют на лету перечитывать токен и скорее всего вам потребуется вручную перезапустить контейнеры, где они используются:

kubectl get pod --field-selector 'spec.serviceAccountName!=default' --no-headers --all-namespaces | awk '{print "kubectl delete pod -n " $1 " " $2}'

Например эта команда выведет список команд для удаления всех подов использующих недефолтный serviceAccount. Рекомендую начать с неймспейса kube-system, т.к. там могут быть установлен kube-proxy и CNI-плагин, жизненно необходимые для настройки коммуникации ваших микросервисов.

На этом восстановление кластера можно считать оконченным. Спасибо за внимание! В следующей статье мы подробнее рассмотрим бэкап и восстановление etcd-кластера.

Подробнее..

Перевод Docker Compose от разработки до продакшена

24.07.2020 20:08:25 | Автор: admin

Перевод транскрипции подкаста подготовлен в преддверии старта курса Администратор Linux





Docker Compose это удивительный инструмент для создания рабочего
окружения для стека, используемого в вашем приложении. Он позволяет вам определять
каждый компонент вашего приложения, следуя четкому и простому синтаксису в YAML-
файлах
.


С появлением docker compose v3 эти YAML-файлы могут использоваться непосредственно в рабочей среде, при работе с
кластером Docker Swarm.


Но значит ли это, что вы можете использовать один и тот же docker-compose файл в
процессе разработки и в продакшен среде? Или использовать этот же файл для
стейджинга? Ну, в целом да, но для такого функционала нам необходимо следующее:


  • Интерполяция переменных: использование переменных среды для некоторых
    значений, которые изменяются в каждой среде.
  • Переопределение конфигурации: возможность определить второй (или любой
    другой последующий) docker-compose файл, который что-то изменит относительно
    первого, и docker compose позаботится о слиянии обоих файлов.

Различия между файлами для разработки и продакшена


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


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


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


Переопределение конфигурации


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


Docker compose поддерживает объединение различных compose-файлов для
получения окончательной конфигурации. Как это работает можно увидеть на примере:


$ cat docker-compose.ymlversion: "3.2"services:  whale:    image: docker/whalesay    command: ["cowsay", "hello!"]$ docker-compose upCreating network "composeconfigs_default" with the default driverStarting composeconfigs_whale_1Attaching to composeconfigs_whale_1whale_1  |  ________whale_1  | < hello! >whale_1  |  --------whale_1  |     \whale_1  |      \whale_1  |       \whale_1  |                     ##        .whale_1  |               ## ## ##       ==whale_1  |            ## ## ## ##      ===whale_1  |        /""""""""""""""""___/ ===whale_1  |   ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~whale_1  |        \______ o          __/whale_1  |         \    \        __/whale_1  |           \____\______/composeconfigs_whale_1 exited with code 0

Как было сказано, docker compose поддерживает объединение нескольких compose-
файлов, это позволяет переопределять различные параметры во втором файле. Например:


$ cat docker-compose.second.ymlversion: "3.2"services:  whale:    command: ["cowsay", "bye!"]$ docker-compose -f docker-compose.yml -f docker-compose.second.yml upCreating composeconfigs_whale_1Attaching to composeconfigs_whale_1whale_1  |  ______whale_1  | < bye! >whale_1  |  ------whale_1  |     \whale_1  |      \whale_1  |       \whale_1  |                     ##        .whale_1  |               ## ## ##       ==whale_1  |            ## ## ## ##      ===whale_1  |        /""""""""""""""""___/ ===whale_1  |   ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~whale_1  |        \______ o          __/whale_1  |         \    \        __/whale_1  |           \____\______/composeconfigs_whale_1 exited with code 0

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


К счастью, docker compose автоматически ищет специальный файл с именем
docker-compose.override.yml для переопределения значений docker-compose.yml. Если
переименовать второй файл, то получится тот же результат, только с помощью изначальной команды:


$ mv docker-compose.second.yml docker-compose.override.yml$ docker-compose upStarting composeconfigs_whale_1Attaching to composeconfigs_whale_1whale_1  |  ______whale_1  | < bye! >whale_1  |  ------whale_1  |     \whale_1  |      \whale_1  |       \whale_1  |                     ##        .whale_1  |               ## ## ##       ==whale_1  |            ## ## ## ##      ===whale_1  |        /""""""""""""""""___/ ===whale_1  |   ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~whale_1  |        \______ o          __/whale_1  |         \    \        __/whale_1  |           \____\______/composeconfigs_whale_1 exited with code 0

Хорошо, так запомнить проще.


Интерполяция переменных


Файлы конфигурации поддерживают интерполяцию
переменных
и значения по умолчанию. То есть вы можете сделать следующее:


services:  my-service:    build:      context: .    image: private.registry.mine/my-stack/my-service:${MY_SERVICE_VERSION:-latest}...

И если вы выполняете docker-compose build (или push) без переменной окружения
$MY_SERVICE_VERSION, будет использовано значение latest, но если вы установите
значение переменной окружения до сборки, оно будет использовано при сборке или пуше
в регистр private.registry.mine.


Мои принципы


Подходы, которые удобны для меня, могут пригодиться и вам. Я следую этим
простым правилам:


  • Все мои стеки для продакшена, разработки (или других сред) определяются через
    файлы docker-compose.
  • Файлы конфигурации, необходимые для охвата всех моих сред, максимально
    избегают дублирования.
  • Мне нужна одна простая команда для работы в каждой среде.
  • Основная конфигурация определяется в файле docker-compose.yml.
  • Переменные среды используются для определения тегов образов или других
    переменных, которые могут меняться от среды к среде (стейджинг, интеграция,
    продакшен).
  • Значения переменных для продакшена используются в качестве значений по
    умолчанию, это минимизирует риски в случае запуска стека в продакшене без
    установленной переменной окружения.
  • Для запуска сервиса в продакшен-среде используется команда docker stack deploy compose-file docker-compose.yml --with-registry-auth my-stack-name.
  • Рабочее окружение запускается с помощью команды docker-compose up -d.

Давайте посмотрим на простой пример.


# docker-compose.yml...services:  my-service:    build:      context: .    image: private.registry.mine/my-stack/my-service:${MY_SERVICE_VERSION:-latest}    environment:      API_ENDPOINT: ${API_ENDPOINT:-https://production.my-api.com}...

И


# docker-compose.override.yml...services:  my-service:    ports: # This is needed for development!      - 80:80    environment:      API_ENDPOINT: https://devel.my-api.com    volumes:      - ./:/project/src...

Я могу использовать docker-compose (docker-compose up), чтобы запустить стек в
режиме разработки с исходным кодом, смонтированным в /project/src.


Я могу использовать эти же файлы на продакшене! И я мог бы использовать точно
такой же файл docker-compose.yml для стейджинга. Чтобы развернуть это на
продакшен, мне просто нужно собрать и отправить образ с предопределенным тегом
на этапе CI:


export MY_SERVICE_VERSION=1.2.3docker-compose -f docker-compose.yml builddocker-compose -f docker-compose.yml push

На продакшене это можно запустить с помощью следующих команд:


export MY_SERVICE_VERSION=1.2.3docker stack deploy my-stack --compose-file docker-compose.yml --with-registry-auth

И если вы хотите сделать то же самое на стейдже, необходимо просто определить
необходимые переменные окружения для работы в среде стейджинга:


export MY_SERVICE_VERSION=1.2.3export API_ENDPOINT=http://staging.my-api.comdocker stack deploy my-stack --compose-file docker-compose.yml --with-registry-auth

В итоге мы использовали два разных docker-compose файла, которые без
дублирования конфигураций могут использоваться для любой вашей среды!




Узнать подробнее о курсе Администратор Linux



Подробнее..

Категории

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

  • Имя: Макс
    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