Расширяя ответ Питера Грейнджера, я смог использовать многоступенчатую сборку, доступную с Docker 17.05. Официальная страница гласит:
В многоэтапных сборках вы используете несколько FROM
операторов в вашем Dockerfile. Каждая FROM
инструкция может использовать различную базу, и каждая из них начинает новый этап сборки. Вы можете выборочно копировать артефакты с одного этапа на другой, оставляя после себя все, что вам не нужно, в конечном изображении.
Имея это в виду, вот мой пример Dockerfile
включения трех этапов сборки. Он предназначен для создания производственного образа клиентского веб-приложения.
# Stage 1: get sources from npm and git over ssh
FROM node:carbon AS sources
ARG SSH_KEY
ARG SSH_KEY_PASSPHRASE
RUN mkdir -p /root/.ssh && \
chmod 0700 /root/.ssh && \
ssh-keyscan bitbucket.org > /root/.ssh/known_hosts && \
echo "${SSH_KEY}" > /root/.ssh/id_rsa && \
chmod 600 /root/.ssh/id_rsa
WORKDIR /app/
COPY package*.json yarn.lock /app/
RUN eval `ssh-agent -s` && \
printf "${SSH_KEY_PASSPHRASE}\n" | ssh-add $HOME/.ssh/id_rsa && \
yarn --pure-lockfile --mutex file --network-concurrency 1 && \
rm -rf /root/.ssh/
# Stage 2: build minified production code
FROM node:carbon AS production
WORKDIR /app/
COPY --from=sources /app/ /app/
COPY . /app/
RUN yarn build:prod
# Stage 3: include only built production files and host them with Node Express server
FROM node:carbon
WORKDIR /app/
RUN yarn add express
COPY --from=production /app/dist/ /app/dist/
COPY server.js /app/
EXPOSE 33330
CMD ["node", "server.js"]
.dockerignore
повторяет содержимое .gitignore
файла (предотвращает копирование node_modules
и последующие dist
каталоги проекта):
.idea
dist
node_modules
*.log
Пример команды для построения изображения:
$ docker build -t ezze/geoport:0.6.0 \
--build-arg SSH_KEY="$(cat ~/.ssh/id_rsa)" \
--build-arg SSH_KEY_PASSPHRASE="my_super_secret" \
./
Если ваш закрытый ключ SSH не имеет парольной фразы, просто укажите пустой SSH_KEY_PASSPHRASE
аргумент.
Вот как это работает:
1). Только на первом этапеpackage.json
, yarn.lock
файлы и секретный ключ SSH копируются первым промежуточным изображением имени sources
. Чтобы избежать дальнейших запросов парольной фразы ключа SSH, она автоматически добавляется в ssh-agent
. в заключениеyarn
команда устанавливает все необходимые зависимости от NPM и клонирует частные репозитории git из Bitbucket через SSH.
2). Второй этап создает и минимизирует исходный код веб-приложения и помещает его в dist
каталог следующего промежуточного изображения с именем production
. Обратите внимание, что исходный код установленnode_modules
скопирован из образа с именем, sources
созданным на первом этапе этой строкой:
COPY --from=sources /app/ /app/
Возможно, это также может быть следующая строка:
COPY --from=sources /app/node_modules/ /app/node_modules/
У нас есть только node_modules
каталог из первого промежуточного изображения здесь, нет SSH_KEY
иSSH_KEY_PASSPHRASE
аргументов больше. Все остальное, необходимое для сборки, скопировано из каталога нашего проекта.
3). На третьем этапе мы уменьшаем размер конечного изображения, которое будет помечено как ezze/geoport:0.6.0
включающее толькоdist
каталог из второго промежуточного изображения с именем production
и устанавливая Node Express для запуска веб-сервера.
Список изображений дает вывод, как это:
REPOSITORY TAG IMAGE ID CREATED SIZE
ezze/geoport 0.6.0 8e8809c4e996 3 hours ago 717MB
<none> <none> 1f6518644324 3 hours ago 1.1GB
<none> <none> fa00f1182917 4 hours ago 1.63GB
node carbon b87c2ad8344d 4 weeks ago 676MB
где немаркированные изображения соответствуют первому и второму промежуточным этапам сборки.
Если вы бежите
$ docker history ezze/geoport:0.6.0 --no-trunc
Вы не увидите никаких упоминаний SSH_KEY
и SSH_KEY_PASSPHRASE
в конечном изображении.