Если вы занимаетесь разработкой Frontend Web, вы знаете, что вы должны сохранить аспект вашего приложения настраиваемого. Наиболее очевидным случай этой конфигурации является базовый URL API. Вы должны определить его таким образом, чтобы вы могли передать его как переменную среды в процессе сборки.
Когда вы строете с Docker, это означает, что это становится аргументом сборки, в отличие от аргумента контейнера.
Это не идеально. Потому что тогда у вас должен быть отдельный и другой образ докера для каждой среды (скажем, Canary, постановка и производство).
Я буду делиться с вами решением, которое я придумал, чтобы решить это во всех наших проектах Frontend. Я буду использовать угловой проект, чтобы проиллюстрировать.
Первое решение, которое у меня было, это включить скрипт для создания определенной среды. Вспомогательный файл до процесса сборки.
Вот как это выглядит как:
// FILE: front/scripts/set-env.ts import { writeFile } from 'fs'; import { argv } from 'yargs'; // This is good for local dev environments, when it's better to // store a projects environment variables in a .gitignore'd file require('dotenv').config(); // Would be passed to script like this: // `ts-node set-env.ts --environment=dev` // we get it from yargs's argv object const environment = argv.environment; const isProd = environment === 'prod'; const targetPath = environment === 'dev' ? `./src/environments/environment.ts` : `./src/environments/environment.${environment}.ts`; const envConfigFile = ` export const environment = { production: ${isProd}, apiBaseUrl: '${process.env.API_BASE_URL}', version: 'v${require('../package.json').version}' }; `; writeFile(targetPath, envConfigFile, function (err) { if (err) { console.log(err); } console.log(`Output generated at ${targetPath}`); });
И я управляю сценарием в процессе сборки Docker, как следующее:
# FILE: Dockerfile ### STAGE 1: Build ### # We label our stage as 'builder' FROM node:10-alpine as builder ARG NODE_ENV ARG API_BASE_URL ENV NODE_ENV "$NODE_ENV" ENV API_BASE_URL "$API_BASE_URL" COPY package.json package-lock.json ./ RUN npm set progress=false && npm config set depth 0 && npm cache clean --force RUN npm install -g ts-node yargs dotenv typescript@2.4.2 ## Storing node modules on a separate layer will prevent unnecessary npm installs at each build RUN npm i && mkdir /ng-app && cp -R ./node_modules ./ng-app WORKDIR /ng-app COPY . . ## Build the angular app in production mode and store the artifacts in dist folder RUN ts-node ./scripts/set-env.ts --environment=prod #actually this is defined as a script in package.json, let's add it here so things would make sense. RUN npm run build ### STAGE 2: Setup ### FROM nginx:1.13.3-alpine ## Copy our default nginx config COPY nginx/default.conf /etc/nginx/conf.d/ ## Remove default nginx website RUN rm -rf /usr/share/nginx/html/* ## From 'builder' stage copy over the artifacts in dist folder to default nginx public folder COPY --from=builder /ng-app/dist /usr/share/nginx/html CMD ["nginx", "-g", "daemon off;"]
В конце концов, мы в конечном итоге с очень маленьким файлом Docker, содержащем Nginx и только артефакты сборки. Нет node_modules, нет nodejs, ничего. Это хорошо, пока вы не хотите использовать то же изображение для нескольких сред. Первая идея пришла в голову, состоит в том, чтобы убить этот процесс сборки 2 шага и просто отправить фактический угловой код и обслуживать его на лету с помощью любой конфигурации выполнения. Верно?
Единственная проблема в том, что изображение докера получит больше в 200 раз больше, и это большой нет нет.
Давайте использовать некоторые навыки Linux и выясните, как мы могли бы изменить URL-адрес API в скомпилированных файлах JavaScript!
Во-первых, этот старый скрипт становится таким:
// FILE: front/scripts/set-env.ts ... export const environment = { production: ${isProd}, apiBaseUrl: 'API_BASE_URL', version: 'v${require('../package.json').version}' }; `; ...
В основном мы передаем эту строку 'Api_base_url'
в конфигурации.
Далее нам нужно найти и заменить эту строку в каждом скомпилированном файле JavaScript в полученном изображении. Давайте сделаем небольшую регулировку в DockerFile:
# FILE: Dockerfile ... COPY --from=builder /ng-app/dist /usr/share/nginx/html COPY --from=builder /ng-app/scripts/replace_api_url.sh / CMD ["sh", "replace_api_url.sh"]
Мы сделали 2 вещи здесь:
- Добавлен новый сценарий под названием
Заменить_api_url.sh
что мы увидим через минуту - И заменил командную строку, поэтому она больше не будет запускать Nginx напрямую, вместо этого мы хотим выполнить наш вновь добавленный скрипт.
Наконец, это выглядит новый скрипт:
// FILE: front/scripts/replace_api_url.sh #!/usr/bin/env sh find '/usr/share/nginx/html' -name '*.js' -exec sed -i -e 's,API_BASE_URL,'"$API_BASE_URL"',g' {} \; nginx -g "daemon off;"
Итак, мы запускаем Nginx в конце, но мы ожидаем переменной среды во время выполнения заменить каждое возникновение API_BASE_URL
во всех файлах JS.
Теперь вам нужно только передать любой URL-адрес API при запуске нового контейнера Docker!
docker run -p 3000:3000 -e API_BASE_URL=http://myawesomebackend.com/api front
Вот и все!
Спасибо за чтение, это мой первый пост здесь и хотел бы получить свой отзыв, поэтому я могу продолжать писать лучше и лучше здесь.
Кредит: обложка изображения от https://medium.com/developer-diary/quick-start-guide-for-docker-with-angular-on-windows-492263edeaf8
Оригинал: «https://dev.to/jaceromri/dynamic-api-url-for-your-frontend-project-using-docker-39n0»