Розгортаючи відповідь Пітера Грінгера, я зміг використовувати багатоетапну збірку, доступну з Докера 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
в кінцевому зображенні.