Пользовательское Docker изображение с Azure базой CLI для аутентификации - PullRequest
0 голосов
/ 19 февраля 2020

Я создаю. NET Базовое приложение, которое я хотел бы развернуть через Azure Devops build pipe. Конвейер будет собираться, тестироваться и развертываться с использованием Docker контейнеров.

Я успешно создал первый docker образ для своего приложения, используя следующий Dockerfile, и сейчас пытаюсь запустить его на своем локальном компьютере. перед его использованием в конвейере:

FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env
MAINTAINER yummylumpkins <yummy@lumpkins.com>
WORKDIR /app

COPY . ./
RUN dotnet publish MyAPIApp -c Release -o out

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
WORKDIR /app
COPY --from=build-env /app/out .

ENTRYPOINT ["dotnet", "MyAPIApp.dll"]

При локальном запуске этого образа в контейнере docker происходит сбой, поскольку мое приложение использует AzureServiceTokenProvider() для попытки получить токен из Azure Сервисов, которые затем будут использоваться чтобы извлечь секреты из Azure Key Vault. Локальный контейнер docker, из которого запускается образ, не имеет прав доступа к Azure Сервисам. Вывод ошибки контейнера docker выглядит следующим образом:

 ---> Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProviderException: Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/XXXX-XXXX-XXXX-XXXX. Exception Message: Tried the following 3 methods to get an access token, but none of them worked.
Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/XXXX-XXXX-XXXX-XXXX. Exception Message: Tried to get token using Managed Service Identity. Access token could not be acquired. Connection refused
Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/XXXX-XXXX-XXXX-XXXX. Exception Message: Tried to get token using Visual Studio. Access token could not be acquired. Environment variable LOCALAPPDATA not set.
Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/XXXX-XXXX-XXXX-XXXX. Exception Message: Tried to get token using Azure CLI. Access token could not be acquired. /bin/bash: az: No such file or directory

После долгих исследований (и получения положительного отзыва здесь) может показаться, что лучший способ авторизовать локально работающий контейнер docker состоит в том, чтобы создать образ поверх базового образа CLI Azure от Microsoft, а затем использовать az login --service-principal -u <app-url> -p <password-or-cert> --tenant <tenant> где-нибудь в процессе сборки / запуска для авторизации локального контейнера docker.

Я успешно вытащил Azure Образ CLI от Microsoft (docker pull mcr.microsoft.com/azure-cli) и может запускать его через docker run -it mcr.microsoft.com/azure-cli. Контейнер работает с командной строкой Azure CLI, и я могу войти через bash, но это все, что я понял.

Следующим шагом будет добавление этого Azure CLI-образа в мой предыдущий Dockerfile во время сборки образа, но я не уверен в этом. Я пробовал следующее:

# New base image is now Azure CLI
FROM mcr.microsoft.com/azure-cli
RUN az login -u yummylumpkins -p yummylumpkinspassword

FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env
MAINTAINER yummylumpkins <yummy@lumpkins.com>
WORKDIR /app

COPY . ./
RUN dotnet publish MyAPIApp -c Release -o out

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
WORKDIR /app
COPY --from=build-env /app/out .

ENTRYPOINT ["dotnet", "MyAPIApp.dll"]

Но это все равно не работает, процесс все равно приводит к той же ошибке, упомянутой выше (я думаю, потому что логин не сохраняется при добавлении нового dotnet core Мой вопрос заключается в том, как мне явно встроить Azure CLI-образ в свой процесс создания dockerfile / image с помощью команды azure login, чтобы авторизовать контейнер docker, сохранить авторизацию, а затем задать команду для запуска приложения. (MyAPIApp.dll) с сохраненной авторизацией?

Или я использую совершенно неправильный подход? Заранее благодарен за любые отзывы.

1 Ответ

1 голос
/ 23 февраля 2020

Размещение обновления с ответом здесь на тот случай, если у кого-то еще возникнет подобная проблема. Я не нашел других решений для этого, поэтому я должен был сделать свое собственное. Ниже мой Dockerfile. Прямо сейчас размер изображения составляет 1 ГБ, поэтому мне, безусловно, потребуется go и оптимизировать его, но я объясню, что я сделал:

#1 Install .NET Core SDK Build Environment
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env
WORKDIR /app

#2 Build YummyApp
COPY . ./
RUN dotnet publish YummyAppAPI -c Release -o out

#3 Install Ubuntu Base Image
FROM ubuntu:latest
MAINTAINER yummylumpkins <yummy@lumpkins.com>
WORKDIR /app
ENV ASPNETCORE_URLS=http://+:80
EXPOSE 80

#4 Install package dependencies & .NET Core SDK
RUN apt-get update \
    && apt-get install apt-transport-https \
    && apt-get update \
    && apt-get install -y curl bash dos2unix wget dpkg \
    && wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb \
    && dpkg -i packages-microsoft-prod.deb \
    && apt-get install -y software-properties-common \
    && apt-get update \
    && add-apt-repository universe \
    && apt-get update \
    && apt-get install apt-transport-https \
    && apt-get update \
    && apt-get install -y dotnet-sdk-3.1 \
    && apt-get update \
    && rm packages-microsoft-prod.deb

#5 Copy project files from earlier SDK build
COPY --from=build-env /app/out .

#6 Install Azure CLI for AppAuthorization
RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash

#7 Login to Azure Services and run application
COPY entrypoint.sh ./
RUN dos2unix entrypoint.sh && chmod +x entrypoint.sh
CMD ["/app/entrypoint.sh"]

Шаг 1. Установка. NET Среда сборки Core SDK: Мы начнем с использования. NET Core SDK в качестве базового образа для сборки моего приложения. Следует отметить, что у меня есть большое приложение с одним решением и несколькими файлами проекта. Проект API зависит от других проектов.

Шаг 2. Построение YummyApp: Мы копируем всю структуру проекта из нашего локального каталога в наш рабочий каталог внутри изображения docker (/ приложение). На всякий случай, если кому-то интересно, мой проект - базовое c API-приложение. Это выглядит так:

[YummyApp]
  |-YummyAppDataAccess
     |YummyAppDataAccess.csproj
  |-YummyAppInfrastructure
     |YummyAppInfrastructure.csproj
  |-YummyAppAPI
    |-YummyAppAPI.csproj
  |-YummyAppServices
    |-YummyAppServices.csproj
  |-YummyApp.sln

После того, как мы скопируем все, мы создаем / publi sh Конфигурацию выпуска приложения.

Шаг 3 - Установите базовый образ Ubuntu : Мы запускаем новый слой, используя Ubuntu. Сначала я попытался go с Alpine Linux, но оказалось, что на него установить Azure CLI практически невозможно без каких-либо по-настоящему хакерских обходных путей, поэтому я пошел с Ubuntu для простоты установки.

Шаг 4. Установка зависимостей пакетов &. NET Core SDK: Внутри слоя Ubuntu мы устанавливаем наш рабочий каталог и устанавливаем / обновляем множество библиотек, включая наш. NET Core SDK. Следует отметить, что мне нужно было установить dos2unix для файла сценария оболочки, который я должен был запустить позже. , .Я объясню позже.

Примечание. Первоначально я пытался установить. NET Core Runtime только из-за его более легкого размера и уменьшения этого образа примерно до 700 МБ (с 1 ГБ), но по какой-то причине, когда я попытался запустить мое приложение в конце файла (Шаг 7) Я получил сообщение об ошибке, в котором не было обнаружено времени выполнения. Поэтому я вернулся к SDK.

Шаг 5. Копирование файлов проекта из более ранней сборки SDK: Чтобы сэкономить место, я скопировал файлы встроенного проекта из первого «образа сборки» в этот слой Ubuntu для экономии места (около 1 ГБ).

Шаг 6 - Установите Azure CLI: Чтобы авторизовать мое приложение для получения токена из Azure Services, обычно я использую Microsoft.Azure.Services.AppAuthentication. Этот пакет предоставляет метод под названием AzureServiceTokenProvider(), который (через мою IDE) разрешает моему приложению подключаться к Azure Services для получения токена, который затем используется для доступа к Azure Key Vault. Вся эта проблема началась, потому что мое приложение не может сделать это из контейнера docker, потому что Azure не распознает запрос, поступающий от самого контейнера.

Итак, в Чтобы обойти это, нам нужно войти через az login в Azure CLI внутри контейнера, прежде чем мы запустим приложение.

Шаг 7 - Войдите в Azure Services и Запустите приложение: Теперь пришло время. У меня были две разные проблемы, чтобы решить здесь. Я должен был выяснить, как выполнить az login и dotnet YummyAppAPI.dll, когда этот контейнер будет запущен. Но Dockerfiles позволяют выполнять только один ENTRYPOINT или CMD во время выполнения, поэтому я нашел обходной путь. Создав файл сценария оболочки (точка входа. sh), я смог поместить обе команды в этот файл и затем выполнить этот один файл.

После настройки я получил ошибку с entrypoint.sh, которая читала что-то вроде этого: entrypoint.sh: executable file not found in $PATH. Я обнаружил, что мне пришлось изменить права доступа к этому файлу с помощью chmod, потому что в противном случае мой контейнер docker не смог получить к нему доступ. Это сделало файл видимым, но файл все еще не мог быть выполнен. Я получаю еще одну ошибку: Standard_init_linux.go:211: exec user process caused “no such file or directory”

После еще одного копания оказывается, что эта проблема возникает, когда вы пытаетесь использовать файл. sh, созданный в Windows на основе Linux система. Поэтому мне пришлось установить dos2unix, чтобы преобразовать этот файл во что-то Linux совместимое. Я также должен был убедиться, что файл был отформатирован правильно. Для любого любопытного, вот как выглядит мой entrypoint.sh:

#!/bin/sh
set -e

az login -u yummy@lumpkins.com -p ItsAlwaysYummy
dotnet /app/YummyAppAPI.dll

exec "$@"

Примечание: Логин и пароль жестко запрограммированы. , Я знаю, что это плохая практика (на самом деле, это ужасно), однако, это только для моей локальной машины и никогда не увидит производство. Следующим шагом будет введение переменных среды с принципом входа в систему. Поскольку это развертывание в конечном итоге произойдет в конвейере Devops * 1095, я могу внедрить эти переменные ENV прямо в конвейер devam YAML, чтобы все это происходило без ввода учетных данных; они будут доставлены прямо из хранилища ключей, где они хранятся.

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

Еще раз спасибо всем.

...