Несколько месяцев назад я писал о том, как я создал игру Snake на основе React. В игру можно играть на http://sean-snake.netlify.com/.
Вы могли заметить, что я полагаюсь на Netlify, чтобы справиться с тяжелой работой по размещению игры и сделать ее доступной для всех, у кого есть доступ в Интернет. Все, что мне нужно было сделать, это связать репозиторий проекта GitHub с Netlify, и все заработало в мгновение ока.
В какой-то момент я задумался, что бы я сделал, если бы захотел больше участвовать в процессе развертывания приложения и его размещения где-нибудь в облаке.
Первый вариант, который пришел в голову, — создать виртуальную машину с помощью AWS, GCP или чего-то подобного. Затем изнутри виртуальной машины я мог клонировать репозиторий, создать приложение и запустить его оттуда. Я делал это раньше, когда мне нужно было разместить бэкэнд-скрипт моего Discord-бота (подробнее об этом можно прочитать здесь). Хотя не было ничего плохого в том, чтобы развернуть экземпляр виртуальной машины и запустить веб-приложение из этого экземпляра, на этот раз я хотел попробовать что-то другое.
На этот раз я решил докеризировать свое приложение!
Напишите Dockerfile
Во-первых, мне нужно было придумать Dockerfile, из которого будет собираться Docker-образ. Dockerfile должен будет сделать следующее:
- Вытяните образ узла
- Скопируйте весь исходный код в рабочий каталог внутри изображения.
- Установите зависимости на основе содержимого
package.json
- Запустите приложение так, как я обычно запускаю его в своей локальной среде.
Ниже приведено содержимое файла Dockerfile.
# Fetching the latest node image on alpine linux FROM node:alpine AS development # Declaring env ENV NODE_ENV development # Setting up the work directory WORKDIR /react-app # Installing dependencies COPY ./package.json /react-app RUN npm install # Copying all the files in our project COPY . . # Starting our application CMD npm run dev
Все выглядело хорошо, когда я построил образ
docker build -f Dockerfile -t seanluong/snake:v1 .
Поиск неисправностей
Это было почти правильно. Когда я использовал docker run
ниже, чтобы запустить приложение:
docker run -d -p 8888:8888 seanluong/snake:v1
и перешел к localhost:8888
, игра Snake не была запущена.
Причина, по которой это не сработало, заключалась в том, что приложение React было создано с использованием Vite, что означает:
- По умолчанию работает не на порту 8888, а на порту 5173.
- Порт не отображается, если при запуске приложения не установлен правильный флаг.
Обновите порт в конфигурации Vite
Я обновил vite.config.ts
, чтобы установить порт по умолчанию как 8888.
import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], server: { port: 8888, }, })
Обновите Dockerfile, чтобы открыть порт
Затем я обновил Dockerfile, чтобы команда запуска приложения включала необходимый флаг для предоставления доступа к порту.
# <same content as before except the last line> # Starting our application. The "-- --host" helps exposing the port CMD npm run dev -- --host
И вуаля!
Все упомянутые здесь изменения можно найти в этом коммите.
Улучшение
Одна из проблем с этим способом докеризации приложения заключается в том, что он не очень эффективен с точки зрения использования дискового пространства. Беглый взгляд на размер изображения сказал мне, что его размер составляет 465 МБ.
% docker images REPOSITORY TAG IMAGE ID CREATED SIZE seanluong/snake v1 7e297431ed1a 23 hours ago 465MB
Это не должно вызывать удивления. Если мы посмотрим на содержимое Dockerfile, то увидим, что здесь нет шага сборки. Исходный код просто копируется и запускается так же, как он обычно запускается в локальной среде без Docker.
Один из способов уменьшить размер изображения — выполнить этап сборки, чтобы весь код React (как TypeScript, так и CSS) был объединен в артефакты сборки, которые будут использоваться как статические ресурсы с веб-сервера (например, nginx
). Это будет темой для другого поста.