Мы продолжаем наш путь к Continuous Delivery (CD) и High Availability (HA), основанной на избыточности. В предыдущей серии мы перевели API для мобильного приложения на .NET Core. Следующий логичный шаг для достижения CD — настроить сборку в Docker-контейнер.
Сегодня поделимся нашим getting-started гайдом по настройке сборки docker-образов и деплоя в Kubernetes в TFS для разработчиков .NET.
(Предполагается, что к этому моменту вы уже мигрировали ваше ASP.NET приложение на ASP.NET Core, а если нет, читайте нашу прошлую статью).
Настройка ASP.NET приложения на работу с Docker
- В Visual Studio 2017 правой кнопкой по web проекту -> Add -> Docker Support;
- Для VS2015 нужно дополнительно поставить расширение.
- В папку с проектом добавится файл Dockerfile – это конфиг для создания образа нашего приложения.
- Подробнее о Docker можно почитать здесь.
- Добавится новый проект docker-compose.
- Сама по себе docker-compose – это утилита для управления мульти-контейнерными приложениями. Например, вы запускаете приложение и СУБД к нему.
- Файлы в проекте:
a. docker-compose.yml – описание ваших сервисов/зависимостей.
Вот пример ASP.NET приложения в связке с SQL Server:
version: '3'
services:
agentrequests.webapp:
image: agentrequests.webapp
build:
context: .
dockerfile: AgentRequests.WebApp/Dockerfile
depends_on:
- agentrequests-db
agentrequests-db:
image: microsoft/mssql-server-linux
environment:
SA_PASSWORD: "<YourStrong!Passw0rd>1"
ACCEPT_EULA: "Y"
ports:
- "1401:1433"
volumes:
- agent-requests-db-data:/var/opt/mssql
volumes:
agent-requests-db-data:
Имена сервисов (в примере БД — agentrequests-db) можно использовать напрямую в вашем приложении, этакий Server Side Service Discovery.
К примеру, строка соединения до базы – "Server=agentrequests-db;Database=AgentRequests;User=sa;Password=<YourStrong!Passw0rd>1;"
b. docker-compose.override.yml – этот файл используется при разработке. Visual Studio мержит эти файлы, когда жмёте F5.
HINT: При каждом изменении docker-compose.yml приложению будет назначаться новый локальный порт, что быстро надоедает при дебаге. Поэтому в docker-compose.override.yml полезно зафиксировать порт вашего приложения:
version: '3'
services:
agentrequests.webapp:
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
- "40005:80"
c. docker-compose.ci.build.yml – с этим конфигом можно сбилдить ваше приложение на CI, и результат будет аналогичным локальному билду. Этот файл нужен, если вы просто деплоите готовые файлы, например, в IIS. Мы же собираемся поставлять готовые docker-образы и будем использовать Dockerfile напрямую.
Промежуточный итог: делаем проект docker-compose стартовым, жмём F5 и радуемся.
NOTE: Первый запуск может оказаться долгим, поскольку докеру нужно скачать образы SQL/ASP.Net Core.
Также при дебаге Visual Studio не создаёт новый докер-образ при каждом изменении кода приложения – на самом деле, создаётся только один контейнер из вашего Dockerfile, к которому монтируется папка c вашими исходниками на хост-машине. Таким образом, каждое изменение, например, js-файла, мгновенно отразится даже на запущенном контейнере.
Сборка и деплой Docker-образов в TFS
CI предполагает, что у нас есть build-машина для выполнения автоматизированных сборок независимо от разработчика. Разработчики заливают свои изменения в систему контроля версиями, build-машина берет последние изменения и пересобирает проект. Таким образом, на build-машине должны быть все необходимые инструменты для сборки проекта. В нашем случае она должна иметь доступ к Docker, чтобы собирать Docker-образы.
Есть несколько вариантов:
Мы можем поставить Docker непосредственно на build-машину либо удаленно подключаться к Docker на другой машине через Docker-клиент. Изначально у нас была стандартная разработка .Net на Windows, поэтому все build-машины представляли собой виртуальные машины Windows с одним или несколькими build-агентами. Чтобы Docker мог собирать Linux-контейнеры на Windows-машине, докер устанавливает виртуальную машину с Linux. Получается, что у нас будет несколько вложенных друг в друга виртуальных машин. Но что-то не хочется начинать городить огороды, и Docker официально не поддерживает такой режим.
Чтобы подключиться к Docker на другой машине, нужно настраивать удаленный доступ, по умолчанию он выключен. Также рекомендуется обеспечить безопасность TLS сертификатам. Еще есть инструкция от Microsoft, в которой предлагается упрощенный вариант настройки с помощью windows-контейнера с предустановленной LibreSSL.
- Наиболее простой способ: build-агент можно запустить прямо в Docker-контейнере, и он будет иметь доступ к Docker, на котором запущен. Достаточно выбрать нужный контейнер из репозитория microsoft/vsts-agent.
Настройка билд-агента
- Скачиваем билд-агент.
- Про различия версий образов и параметры можно прочитать тут.
- Нужна версия c docker'ом на борту, к примеру:
docker pull microsoft/vsts-agent:ubuntu-16.04-tfs-2017-u1-docker-17.12.0-ce - Генерим Personal Access Token (PAT) в на странице Security в TFS:
- Можно добавить новый Agent Pool для сборок докера. Делается это здесь:
- Запускаем контейнер:
docker run \ -e TFS_URL=<YOUR_TFS_URL> \ -e VSTS_TOKEN=<PAT> \ -e VSTS_POOL=<POOL> -e VSTS_AGENT=$(hostname)-agent \ -v /var/run/docker.sock:/var/run/docker.sock \ --restart=always -it microsoft/vsts-agent:ubuntu-16.04-tfs-2017-u1-docker-17.12.0-ce
Настройка CI
- В проекте в TFS добавляем новый Build Definition с темплейтом – Container (PREVIEW)
- Таска build image:
a. Container Registry Type – Container Registry;
b. Docker Registry Connection – здесь настраиваем путь до вашего реестра образов. Можно использовать и Docker Hub, но мы в компании используем Nexus Registry;
c. Docker File – путь до докер файла. Лучше указать путь явно, без маски;
d. Use Default Build Context – снимаем галочку;
e. Build Context – путь до папки, в которой лежит ваш .sln файл;
f. Image-name – лучше задать явно, все символы в нижнем регистре. Пример: groups/agent-requests:$(Build.BuildId);
g. Можно поставить include latest tag – будет обновляться latest тег в реестре. - Таска push an image — аналогично второму пункту. Главное, не забыть поменять image name.
- Добавить таску с темплейтом Publish Build Artifacts. Поскольку мы планируем деплоить в kubernetes, нашим артефактом будет конфиг для kubectl:
a. Path to Publish – путь до вашего yaml файла с конфигом kubernetes. Можно указать папку, если конфигов несколько;
b. Artifact Name – на ваш вкус. К примеру, kubernetes;
c. Artifact Type – Server.
Настройка CD и Kubernetes
Вначале небольшое отступление. Грубо говоря, docker-compose (swarm) – это конкурент kubernetes. Но поскольку в VS нет удобного тулинга для билда и дебага в kubernetes, то используем оба варианта: compose при разработке, kubernetes на бою.
Приятная новость в том, что есть утилита Kompose – она умеет конвертить Kubernetes конфиги в/из docker-compose.yaml файлы.
Впрочем, не обязательно для девелопа вообще использовать docker/compose – можно настроить всё по старинке и руками менять урлы/конфиги или хранить по десять web.config для разных окружений.
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
type: LoadBalancer
selector:
app: webapp
ports:
- port: 80
Пример deployment.yaml:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: webapp
spec:
replicas: 1
template:
metadata:
labels:
app: webapp
spec:
imagePullSecrets:
- name: <название соединения с Docker Registry>
containers:
- image: webapp
name: webapp
env:
- name: DB_USER
valueFrom:
secretKeyRef:
name: database-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: database-secret
key: password
- name: SQLCONNSTR_<Название сроки подключения>
#например SQLCONNSTR_DefaultConnection
value: "Server=<адрес SQL сервера>;Initial Catalog=<название БД>;Persist Security Info=False;User ID=$(DB_USER);Password=$(DB_PASSWORD);"
ports:
- containerPort: 80
Для настройки CD мы использовали Kubernetes extension для нашего TFS сервера, так как стандартная таска Deploy to Kubernetes, которая идет из коробки, в нашей версии TFS оказалась нерабочей.
- Добавьте в Kubernetes настройки подключения к нашему Docker Registry
kubectl create secret docker-registry <название соединения с Docker Registry>--docker-server=<адрес сервера>--docker-username=<логин>--docker-password=<пароль>--docker-email=<почта>
Добавьте логин и пароль для подключения к базе
kubectl create secret generic database-secret--from-literal=username=<логин>--from-literal=password=<пароль>
Примечание: шаги 1 и 2 так же можно автоматизировать через TFS.
Добавьте Kubernetes endpoint в TFS:
Создайте новый Release Defenition:
a. Выберите проект и Build definition
b. Поставьте галочку Continuous deployment
Добавьте таску kubernetes downloader:
a. В поле “kubernetes end point” выберите ваш kubernetes endpoint
b. В поле “kubectl download version” укажите необходимую версию или оставьте поле пустым, в этом случае будет установлена последняя версия клиента.
Добавьте таску kubectl exec:
a. В поле “Sub Command” пишем: apply
b. В поле “Arguments” пишем: -f $(System.DefaultWorkingDirectory)/<путь к папке с конфигами>/deployment.yaml
Добавьте таску kubectl exec:
a. В поле “Sub Command” пишем: apply
b. В поле “Arguments” пишем: image -f $(System.DefaultWorkingDirectory)/<путь к папке с конфигами>/service.yaml
- Добавьте таску kubectl exec:
a. В поле “Sub Command” пишем: set
b. В поле “Arguments” пишем: image -f $(System.DefaultWorkingDirectory)/<путь к папке с конфигами>/deployment.yaml webapp=webapp:$(Build.BuildID)
Итоги
За сим всё. Используйте docker, автоматизируйте развёртывание и наслаждайтесь лёгким релизом хоть в вечер пятницы, даже перед вашим отпуском.
96467840
месье знает толк в извращениях %)