对 React.js 应用程序进行 Docker 化
在本文中,我们将对一个 React 应用程序进行 docker 化。我们将设置 Docker 的自动重新加载功能,用于开发环境的设置,并针对生产部署优化多阶段 docker 构建。我们甚至可以使用相同的流程对 Next.js 或 Gatsby 静态构建进行 docker 化。
使用 Docker 有很多优势。目前,Docker 已成为容器化应用程序的事实标准。使用 Docker 构建、打包、共享和发布应用程序非常便捷。由于 Docker 镜像具有可移植性,因此可以轻松地将应用程序部署到任何现代云提供商。
初始化 React 应用程序
让我们从创建一个 React 应用程序开始。您可以使用现有的 React 项目。在本篇博文中,我将使用 创建一个全新的 React 应用程序create-react-app
。
$ npx create-react-app react-docker
这里我创建了一个名为 的新 React 应用react-docker
。让我们通过npm start
在项目目录中运行命令来验证该应用。
$ npm start
它将启动应用程序,我们可以通过在浏览器中访问http://localhost:3000来验证。应用程序应该正在运行。
编写 Dockerfile。
现在让我们为 React 应用程序创建一个 Docker 镜像。我们需要一个 Dockerfile 来创建 Docker 镜像。让我们Dockerfile
在 React 应用程序的根目录中创建一个名为的文件。
Dockerfile
FROM node:14-alpine
WORKDIR /app
COPY package.json ./
COPY yarn.lock ./
RUN yarn install --frozen-lockfile
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
这里我们使用 Node v14 Alpine 作为基础镜像来构建和运行应用程序。我们运行的npm start
命令是默认命令,它将运行 React 开发服务器。我们还需要.dockerignore
防止node_modules
其他不需要的文件被复制到 Docker 镜像中。
.dockerignore
node_modules
npm-debug.log
Dockerfile
.dockerignore
让我们通过运行命令从 Dockerfile 构建 Docker 镜像docker build
。这里我们用 name 标记它react-docker
。
$ docker build -t react-docker .
构建完docker镜像后,我们可以通过运行命令来验证镜像docker images
。我们可以看到一个名为 的镜像react-docker
被创建了。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
react-docker latest 6b782301e271 2 minutes ago 438MB
我们可以使用以下命令运行 Docker 镜像。这里我们将系统端口 3000 映射到 Docker 容器端口 3000。我们可以通过访问http://localhost:3000来docker run
验证应用程序是否正在运行。
$ docker run -p 3000:3000 react-docker
添加 Docker Compose
React 应用程序在 docker 容器中运行良好,但每次对源文件进行任何更改时,我们都需要构建并运行 docker 容器,因为自动重新加载功能在这种设置下无法正常工作。我们需要将本地文件夹挂载src
到 docker 容器src
文件夹,这样每次在src
文件夹内进行任何更改时,它都会根据代码更改自动重新加载页面。
我们将文件添加docker-compose.yml
到项目的根目录,以将本地src
文件夹挂载到/app/src
容器的文件夹中。
docker-compose.yml
version: "3"
services:
app:
build:
context: .
dockerfile: Dockerfile
volumes:
- ./src:/app/src
ports:
- "3000:3000"
运行docker-compose up
命令启动容器。React 开发服务器将在容器内运行并监视该src
文件夹。
$ docker-compose up
由于此 Docker 镜像未经优化且内部运行着开发服务器,我们无法将其发布到生产环境。让我们重命名镜像Dockerfile
并Dockerfile.dev
更新docker-compose.yaml
文件以使用该Dockerfile.dev
文件。我们将使用 docker-compose 和该Dockerfile.dev
文件进行开发。我们将为生产环境构建创建一个新的 Dockerfile。
$ mv Dockerfile Dockerfile.dev
docker-compose.yml
version: "3"
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- ./src:/app/src
ports:
- "8000:8000"
添加生产 Dockerfile
yarn build
让我们首先通过运行命令来构建生产应用程序,以验证 React 应用程序生产配置。
$ yarn build
我们可以通过在本地运行来验证生产版本。我用它serve
来提供build
文件夹文件。
$ npx serve -s build
在本地验证服务器后,我们可以为生产环境创建一个新的 Dockerfile。我们将使用多阶段构建来创建 Docker 镜像。一个阶段用于构建生产环境文件,另一个阶段用于提供这些文件。
Dockerfile
FROM node:14-alpine AS builder
WORKDIR /app
COPY package.json ./
COPY yarn.lock ./
RUN yarn install --frozen-lockfile
COPY . .
RUN yarn build
FROM nginx:1.19-alpine AS server
COPY --from=builder ./app/build /usr/share/nginx/html
这个builder
阶段与之前的 Dockerfile 几乎相同。npm start
我们不是在这里运行命令,而是运行yarn build
构建生产文件的命令。
我们将使用Nginx
它来提供文件服务。它将创建一个非常轻量级的镜像。在构建阶段,我们需要将build
文件夹中的文件复制到该/usr/share/nginx/html
文件夹。Nginx Docker 镜像使用此文件夹来提供内容。Nginx Docker 镜像将使用指定的端口80
来提供文件服务,并自动公开该端口。
让我们通过运行命令再次构建图像,docker build
并通过运行命令验证图像是否已构建docker images
。
$ docker build -t react-docker .
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
react-docker latest 5f885aeca09e 7 seconds ago 23.1MB
生产环境的 Docker 镜像比开发环境的镜像要小得多。让我们用以下docker run
命令运行 Docker 镜像。这里我们将主机3000
端口映射到容器的端口。80
docker run -p 3000:80 react-docker
应用程序应该可以在http://localhost:3000上正常运行。现在让我们验证一下客户端路由是否正常工作。为此,我们需要react-router-dom
在应用程序中安装。
$ yarn add react-router-dom
我们还需要添加一些路由和链接来验证。我只是从react-router 官网复制了示例来测试。
import React from "react";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
export default function App() {
return (
<Router>
<div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/users">Users</Link>
</li>
</ul>
</nav>
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/users">
<Users />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
return <h2>Home</h2>;
}
function About() {
return <h2>About</h2>;
}
function Users() {
return <h2>Users</h2>;
}
让我们通过运行开发服务器来验证本地设置,访问网页并单击每个链接并刷新页面。
$ npm start
该应用程序在本地开发服务器上应该可以正常工作。现在尝试使用 docker-compose 进行同样的操作。首先,我们需要重新构建镜像,因为自动重新加载仅适用于src
文件夹,因为我们只挂载了该文件夹。对于文件夹之外的更改src
,我们需要使用命令重新构建镜像docker-compose build
。
$ docker-compose build
$ docker-compose up
现在让我们用生产环境的docker build尝试同样的事情。首先,我们需要构建docker镜像并再次运行该镜像。
docker build -t react-docker .
docker run -p 3000:80 react-docker
直接访问索引以外的页面应该会抛出 404 错误。此处的 React 应用是单页应用。因此,路由是在客户端使用 JavaScript 进行的。当我们访问任何路由时,它首先会访问 Nginx 服务器并尝试在那里查找文件,如果找不到文件,就会抛出 404 错误。
我们需要将自定义的 Nginx 配置传递给 docker 镜像。我们将etc
在项目的根目录中创建一个文件夹,并nginx.conf
在其中创建一个文件。
etc/nginx.conf
server {
listen 80;
listen [::]:80 default ipv6only=on;
root /usr/share/nginx/html;
index index.html;
server_tokens off;
server_name _;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_min_length 0;
gzip_types text/plain application/javascript text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype;
location / {
try_files $uri /index.html;
}
}
这里我们配置了 Nginx,/index.html
当无法找到路由时,它会回退到原来的路由。我们还启用了内容的 gzip 压缩。
我们需要将自定义的 Nginx 配置文件复制到该/etc/nginx/conf.d
文件夹。Ngnix 将自动读取该文件夹中的所有配置。
FROM node:14-alpine AS builder
WORKDIR /app
COPY package.json ./
COPY yarn.lock ./
RUN yarn install --frozen-lockfile
COPY . .
RUN yarn build
FROM nginx:1.19-alpine AS server
COPY ./etc/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder ./app/build /usr/share/nginx/html
复制自定义 Nginx 配置文件后,我们需要再次构建并运行 docker 镜像。
$ docker build -t react-docker .
$ docker run -p 3000:80 react-docker
访问所有路线并刷新页面应该可以正常工作。
本教程的所有源代码均可在GitHub上找到。
对于dockerizing node后端应用程序,请阅读其他博客文章
鏂囩珷鏉ユ簮锛�https://dev.to/rsbh/dockerizing-a-react-js-app-1ca3