Угадай, данную статью написал ChatGPT или нет?
Хотите потестировать приложение, или опробовать в работе инструмент? В этой статье опишу то, как организовал тестовый стенд на Linux. Стенд поддерживает работу с доменами, умеет генерировать TLS сертификаты, легко масштабируется, окружение строится по принципе IaaC, не требует много ресурсов, легко разворачивается скриптами или SCM, есть UI, не зависит от внешних сервисов.
Я являюсь системным инженером и наиболее эффективным языком для инструкций считаю "птичий" технический язык. Содержимое представляет собой последовательность команд с вкраплением комментариев, по которым коллега может однозначно понять этапы построения окружения без лишних слов. А дополнительную информацию о перечисленных инструментах можно легко получить уже из документации и после чего внести правки для тестового стенда. Кроме примеров кода и команд опишу те плюсы и те минусы, которые свойственны этой архитектуре, как бы громко это не звучало.
Конфигурация обыденная и не представляет ценности или сложности с точки зрения моего опыта, но может пригодится начинающим инженерам или даже опытным программистам, которые пишут код для сервисов или используют сервисную архитектуру для решения задач, но не погружаются в технические детали.
Используемые инструменты
Nomad — https://www.nomadproject.io
Consul — https://www.consul.io
Vault — https://www.vaultproject.io
Traefik — https://traefik.io
Packer — https://www.packer.io
Docker — http://docker.io
Плюсы
Набор инструментов с легкостью умещается на небольшой виртуальной машине
Инженер использует на практике современные подходы по релизу и выкладке программного обеспечения
В случае необходимости стенд легко масштабируется в боевое окружение. Отлично подходит для MVP проекта
Минусы
Не подходит для отладки "на лету", но такая возможность есть
Не пользуется популярностью
Краткое описание
Код приложения собирается с помощью Packer в образ и размещается на локальном сервере (аналог Docker Registry). На данном этапе можно потренироваться с версионированием и работой в различных окружениях.
Приложение запускается в виде контейнера Docker и вместе с тем появляется возможность оркестрации, т. е. множественных запусков и стратегий обновления контейнеров с помощью Nomad. Секретные данные передаются в контейнер шаблонами go-template или через переменные окружения из Vault.
В случае Web-приложения или приложения с административным интерфейсом в Traefik создаются точки входа HTTPS с сертификатами TLS от Let'sEncrypt.
Как будет проходить настройка
Я буду приводить примеры установки и настройки сервера для Ubuntu, но различия с другими дистрибутивами будут только на этапе установки пакетов.
Виртуальная машина
Для тестового стенда подойдет виртуальная машина с 2 ядрами, 4Г памяти и диском объемом 20Г. Можете оценить объем используемой памяти на примере моего стенда:
3236 root traefik traefik N/A 1.37% 1.37% 1.37%
3488 root bin/console bot run N/A 1.16% 1.28% 1.42%
3416 root bin/console bot run N/A 1.17% 1.28% 1.42%
858 root /usr/bin/containerd N/A 1.49% 1.49% 1.52%
3300 nobody /bin/prometheus --config.fi N/A 1.56% 1.56% 1.56%
986 root /usr/bin/dockerd -H unix:// N/A 2.13% 2.13% 2.21%
928 consul /usr/bin/consul agent -conf N/A 2.35% 2.35% 2.35%
3840 root /usr/bin/nomad agent -confi N/A 1.57% 1.67% 2.48%
934 vault /usr/bin/vault server -conf N/A 5.45% 5.45% 5.45%
-------------------------------------------------------------------------------
88 12 N/A 25.49% 28.31% 45.90%
Это полностью запущенный стенд состоящий из 5 сервисов на 4Г памяти (45% занято). Дороже всего обходится секретность.
Установка инструментов и репозиториев
https://developer.hashicorp.com/nomad/downloads
https://docs.docker.com/engine/install/ubuntu/
Hidden text
Я не учитываю блокировки доступа из России.
mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
curl -fsSL https://apt.releases.hashicorp.com/gpg | gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com \
$(lsb_release -cs) main" > /etc/apt/sources.list.d/hashicorp.list
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list
Устанавливаем пакеты
apt update
apt install nomad vault consul docker-ce docker-compose packer jq
Настройка Docker + Docker Registry
systemctl start docker
Сейчас нам нужно запустить локальное хранилище образов, которое будет работать идентично публичному облаку или внутреннему в компании.
Создаем файл с описанием сервиса docker-compose.yml
cat >docker-compose.yml <<EndOfText
version: "3.9"
services:
registry:
container_name: registry
image: registry:2
ports:
- 5000:5000
volumes:
- ./config.yml:/etc/docker/registry/config.yml
- /var/lib/registry:/var/lib/registry
EndOfText
И файл с конфигурацией сервиса config.yml
cat >config.yml <<EndOfText
version: 0.1
log:
fields:
service: registry
storage:
cache:
blobdescriptor: inmemory
filesystem:
rootdirectory: /var/lib/registry
http:
addr: :5000
headers:
X-Content-Type-Options: [nosniff]
health:
storagedriver:
enabled: true
interval: 10s
threshold: 3
EndOfText
После запуска наши образы будут храниться в папке /var/lib/registry
Запускаем
docker-compose up -d
Настройка Consul
Генерируем ключ шифрования
CONSUL_KEY=$(consul keygen)
Создаем файл /etc/consul.d/lab_consul.hcl
cat >/etc/consul.d/lab_consul.hcl <<EndOfText
client_addr = "0.0.0.0"
acl {
enabled = true
}
ui_config {
enabled = true
}
bind_addr = "127.0.0.1"
bootstrap_expect = 1
server = true
encrypt = "$CONSUL_KEY"
EndOfText
Запускаем
systemctl restart consul; sleep 10
consul acl bootstrap --format json > ./acl-token-bootstrap-consul.json
export CONSUL_HTTP_TOKEN=`cat ./acl-token-bootstrap-consul.json | jq -r ".SecretID"`
Проверяем
# consul members
Node Address Status Type Build Protocol DC Partition Segment
test 127.0.0.1:8301 alive server 1.14.0 2 dc1 default <all>
Панель по адресу
echo "http://$(curl -s ifconfig.me):8500"
Настройка Vault
Создаем файл /etc/vault.d/vault.hcl
cat >/etc/vault.d/vault.hcl <<EndOfText
ui = true
storage "file" {
path = "/opt/vault/data"
}
listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = "true"
}
api_addr = "http://127.0.0.1:8200"
cluster_addr = "https://127.0.0.1:8201"
EndOfText
Запускаем
systemctl restart vault; sleep 10
export VAULT_ADDR='http://127.0.0.1:8200'
vault operator init -key-threshold 1 -key-shares 1 -format json > ./acl-token-bootstrap-vault.json
export VAULT_TOKEN=$(cat ./acl-token-bootstrap-vault.json | jq -r ".root_token")
export VAULT_UNSEAL_KEY=$(cat ./acl-token-bootstrap-vault.json | jq -r ".unseal_keys_b64 | .[]")
vault operator unseal $VAULT_UNSEAL_KEY
vault login $VAULT_TOKEN
В Vault нам потребуется подключить модуль для хранения наших секретов
vault secrets enable -version=2 kv
Теперь сохраним токен Consul в хранилище Vault
vault kv put kv/consul/token value=$CONSUL_HTTP_TOKEN
Панель по адресу
echo "http://$(curl -s ifconfig.me):8200"
Настройка Nomad
Создаем файл /etc/nomad.d/lab_nomad.hcl
cat >/etc/nomad.d/lab_nomad.hcl <<EndOfText
consul {
address = "127.0.0.1:8500"
token = "$CONSUL_HTTP_TOKEN"
}
acl {
enabled = true
}
telemetry {
publish_allocation_metrics = true
publish_node_metrics = true
}
plugin "docker" {
config {
volumes {
enabled = true
}
}
}
vault {
enabled = true
address = "http://localhost:8200"
token = "$VAULT_TOKEN"
}
EndOfText
Запускаем
systemctl restart nomad; sleep 10
nomad acl bootstrap -json > ./acl-token-bootstrap-nomad.json
export NOMAD_TOKEN=`cat ./acl-token-bootstrap-nomad.json | jq -r ".SecretID"`
Панель по адресу
echo "http://$(curl -s ifconfig.me):4646"
Запуск Traefik
Создаем файл traefik.nomad
export MY_MAIL="some@domain.ltd"
cat >traefik.nomad <<EndOfText
job "traefik" {
datacenters = ["dc1"]
type = "service"
group "traefik" {
count = 1
network {
port "http" {static = 80}
port "https" {static = 443}
port "api" {static = 8081}
}
service {
name = "traefik"
port = "api"
tags = ["traefik.enable=true", "traefik.port=8081"]
}
task "traefik" {
driver = "docker"
config {
image = "traefik:v2.2"
network_mode = "host"
volumes = [ "local/traefik.yaml:/etc/traefik/traefik.yaml" ]
}
template {
destination = "local/traefik.yaml"
data = <<EOF
entryPoints:
http:
address: ':80'
https:
address: ':443'
traefik:
address: ':8081'
api:
dashboard: true
insecure: true
log:
level: DEBUG
certificatesResolvers:
myresolver:
acme:
email: $MY_MAIL
storage: /data/acme.json
httpChallenge:
entryPoint: http
providers:
consulCatalog:
prefix: traefik
exposedByDefault: false
endpoint:
address: 127.0.0.1:8500
scheme: http
token: {{with secret "kv/consul/token"}}{{.Data.data.value}}{{end}}
tls:
insecureSkipVerify: true
EOF
}
}
}
}
EndOfText
Проверяем наш конфиг и применяем
nomad plan traefik.nomad
nomad run traefik.nomad
Панель по адресу
echo "http://$(curl -s ifconfig.me):8081"
Сборка приложения
Создаем файл whoami.pkr.hcl
cat >whoami.pkr.hcl <<EndOfText
packer {
required_plugins {
docker = {
version = ">= 1.0.1"
source = "github.com/hashicorp/docker"
}
}
}
source "docker" "whoami" {
image = "traefik/whoami"
commit = true
run_command = [
"-d", "-i", "--rm", "-t", "--", "{{.Image}}"
]
}
build {
sources = ["source.docker.whoami"]
post-processors {
post-processor "docker-tag" {
repository = "localhost:5000/dev/whoami"
tags = ["0.0.1"]
}
post-processor "docker-push" {}
}
}
EndOfText
И запускаем сборку
packer init .
packer build .
В конце сборки будет указан адрес образа для следующего шага
Запуск тестового приложения
Создаем файл whoami.nomad
cat >whoami.nomad <<EndOfText
job "whoami" {
datacenters = ["dc1"]
type = "service"
group "whoami" {
count = 1
network {
port "http" {to = 80}
}
service {
name = "whoami"
port = "http"
tags = [
"traefik.enable=true",
"traefik.http.routers.whoami.entrypoints=http",
"traefik.http.routers.whoami.rule=host(\`$(curl -s ifconfig.me)\`)",
"traefik.http.routers.whoami.middlewares=whoami-to-https",
"traefik.http.middlewares.whoami-to-https.redirectscheme.scheme=https",
"traefik.http.middlewares.whoami-to-https.redirectscheme.permanent=true",
"traefik.http.routers.whoami-https.entrypoints=https",
"traefik.http.routers.whoami-https.rule=host(\`$(curl -s ifconfig.me)\`)",
"traefik.http.routers.whoami-https.tls.certresolver=myresolver"]
}
task "whoami" {
driver = "docker"
config {
image = "localhost:5000/dev/whoami:0.0.1"
ports = ["http"]
}
}
}
}
EndOfText
Проверяем и запускаем наш сервис
nomad plan whoami.nomad
nomad run whoami.nomad
Проверить можно по адресу
echo "http://$(curl -s ifconfig.me)"
После запуска обработать напильником...
Думаю на примере готового приложения дальше будет разобраться попроще.
Пример скрипта для быстрой настройки стенда
Скрипт не идемпотентный, будте осторожны! Запускайте только на новой виртуальной машине с Ubuntu.
curl https://git.sr.ht/~wilful/Shared/blob/master/init.sh | bash -x
Посмотреть все доступные адреса панелей можно так
journalctl -t laboratory -xe
Что можно улучшить?
https://www.waypointproject.io?
Оригинал тут