使用Docker和Nginx部署单页面应用

发布时间 2023-12-23 18:17:48作者: starlog

使用Docker和Nginx部署单页面应用

一、简介

1.背景

Docker 是一个容器引擎,它使用 Linux 内核功能(如命名空间和控制组)在操作系统之上创建容器

Docker Compose是一个命令行工具,可以简化容器镜像的构建以及容器的运行,将命令行的选项翻译成配置文件

Nginx是一个高性能的HTTP和反向代理服务器

2.Docker基础命令

#构建镜像
docker build [可选参数] 构建上下文目录

#列出所有镜像
docker images

#删除镜像
docker rmi 镜像ID

#启动容器,运行镜像
docker run [可选参数] 镜像

#列出所有正在运行的容器
docker ps

#列出所有容器 
docker ps -a

#停止容器
docker stop [容器ID]

#删除容器
docker rm [容器ID]

docker build的部分可选参数

可选参数 说明
-t 指定镜像标签名
-f 指定其他目录下的Dockerfile文件,可以是远程地址

docker run的部分可选参数

可选参数 说明
-p 指定端口映射,-p 3000:80,把容器的80端口映射到宿主机的3000端口
-d 后台运行
--rm 容器退出时自动删除该容器

二、准备要部署的单页面应用

以create-react-app为例,创建React项目,并执行打包,项目根目录下build文件夹为打包产物,其中index.html为入口文件

在项目文件夹(如D:\Projects),执行以下命令

npx create-react-app app-deploy

cd app-deploy

npm install --registry https://registry.npmmirror.com

npm run build

打包产物如下

三、准备环境(Linux)

以Ubuntu为例

1.安装Docker

进入Docker官方文档:https://docs.docker.com/engine/install/ubuntu/,按照顺序执行文档中的命令,即以下命令

# Add Docker's official GPG key:
# 更新apt软件包索引
sudo apt-get update

# 安装必要的软件包以使用HTTPS源
sudo apt-get install ca-certificates curl gnupg

# 创建一个目录,用于存储Docker GPG密钥
sudo install -m 0755 -d /etc/apt/keyrings

# 从Docker官方站点下载GPG密钥并将其解压缩到前面创建的目录中
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# 设置密钥文件的权限,允许所有用户读取
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Add the repository to Apt sources:
# 添加Docker软件包源列表
echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 再次更新apt软件包索引
sudo apt-get update

# 安装所需的Docker软件包及插件
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

安装完成后,执行以下命令

sudo docker run hello-world

出现以下输出说明Docker安装成功

image

2.安装Docker-Compose

1)安装pip(如果没有安装的话)

sudo apt install -y python3-pip

2)安装Docker-Compose

sudo pip install docker-compose -i https://mirrors.aliyun.com/pypi/simple/

安装完成后,执行以下命令

docker-compose --version

出现以下输出说明Docker-Compose安装成功

image

3.使用Docker Hub镜像源

编辑以下文件

/etc/docker/daemon.json

在该文件中添加registry-mirrors属性

{
  "registry-mirrors": [
    "https://dockerproxy.com"
  ]
}

然后重新加载Docker Daemon并重启Docker

sudo systemctl daemon-reload # 重新加载Docker Daemon

sudo systemctl restart docker # 重启Docker

4避免Docker磁盘占用空间膨胀

1)限制日志文件的大小和数量

编辑以下文件

/etc/docker/daemon.json

在该文件中添加以下两个属性

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  }
}

然后重新加载Docker Daemon并重启Docker,该配置将对新建的容器生效

sudo systemctl daemon-reload # 重新加载Docker Daemon

sudo systemctl restart docker # 重启Docker

2)定时清理未使用的镜像、容器、网络、构建缓存

# 编辑当前用户的定时任务列表
crontab -e

在打开的定时任务配置文件中添加以下配置

# 每天凌晨1点删除24小时前创建的未使用的镜像、容器、网络、构建缓存
0 1 * * * docker system prune --force --filter "until=24h"
# Linux创建定时任务命令:分 时 天 月 星期 命令
# docker system prune命令是删除未使用的镜像、容器、网络、构建缓存的快捷方式,可以用--filter做过滤

四、准备环境(Windows)

1.安装WSL

1)简介

WSL是“Windows Subsystem for Linux”的缩写,顾名思义,WSL就是Windows系统的Linux子系统,其作为Windows组件搭载在Windows10周年更新(1607)后的Windows系统中

2)操作

进入https://learn.microsoft.com/zh-cn/windows/wsl/install-manual#step-4---download-the-linux-kernel-update-package,执行到步骤5,即WSL安装成功即可

2.安装Docker Desktop

1)简介

Docker Desktop是可以部署在windows运行docker的应用服务,其基于windos的Hyper-V服务和WSL2内核在windos上创建一个子系统(linux),从而实现其在windows上运行docker

必须先安装WSL,否则Docker Desktop无法正常启动Docker

2)操作

进入https://www.docker.com/get-started/,下载并安装

3.验证Docker和Docker-Compose的安装

查看版本并运行HelloWorld

执行以下命令

docker -v

docker-compose -v

docker run hello-world

出现以下输出说明Docker安装成功

image

4.使用Docker Hub镜像源

打开Docker Desktop,点击设置按钮,切换到Docker Engine标签,在下面的配置文件中添加registry-mirrors属性

image

{
  "registry-mirrors": [
    "https://dockerproxy.com"
  ]
}

image

然后点击Apply & restart

五、编写相关配置文件

1.编写nginx配置文件

在项目根目录(D:\Projects\app-deploy),新建一个文件,命名为nginx.conf,内容为

server {
    listen       80; #监听本地80端口,由于nginx运行在容器内,这个本地指的是容器
    server_name  localhost;
    root   /usr/share/nginx/html; #为该目录做静态资源服务
    index  index.html index.htm;
    location / {
        try_files  $uri $uri/ /index.html; #在单页面应用中将不存在的资源重定向到root目录下的index.html
        expires -1; #资源默认不缓存,避免浏览器缓存
    }
    location /static {
        expires 1y; #打包产物static文件夹下的文件的名称带有hash值,可设置一年的长期缓存
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

2.编写Dockerfile文件

在项目根目录(D:\Projects\app-deploy),新建一个文件,命名为Dockerfile(没有后缀名),内容为

# 继承nginx:alpine镜像
# Alpine是一种轻量级的Linux发行版,专为作为容器而设计
FROM nginx:alpine

# 将当前目录build文件夹下的所有文件都复制到当前镜像的/usr/share/nginx/html文件夹中
ADD build /usr/share/nginx/html

# 将node镜像/temp文件夹下的nginx.conf文件复制到当前镜像的/etc/nginx/conf.d文件夹中,命名为default.conf
COPY --from=node /temp/nginx.conf /etc/nginx/conf.d/default.conf

3.编写Docker-Compose配置文件

在项目根目录(D:\Projects\app-deploy),新建一个文件,命名为docker-compose.yaml,内容为

version: "3" #使用Docker-Compose的v3版本语法,是目前的主流版本
services:
  app: #服务命名为app
    build: . #从当前路径构建镜像
    ports:
      - 3000:80 #容器与宿主机之间的端口映射,冒号前面是宿主机端口,冒号后面是容器端口,可以配置多个

六、构建镜像并启动容器(部署应用)

使用Docker-Compose或不使用Docker-Compose

1.使用Docker-Compose

在项目根目录(D:\Projects\app-deploy),执行以下命令

docker-compose up --build

#up代表创建并启动容器,--build代表每次启动容器前构建镜像

命令行输出如下

Linux:

image

Windows:

image

在浏览器访问http://localhost:3000,将显示部署成功的单页面应用

image

在浏览器控制台查看响应头,将显示nginx版本信息

image

2.不使用Docker-Compose

在项目根目录(D:\Projects\app-deploy),执行以下命令

# 使用当前目录的Dockerfile文件构建镜像,镜像标签为app
docker build -t app .

#启动容器,运行镜像标签为app的镜像
#-p代表端口,把容器的80端口映射到宿主机的3000端口
docker run -p 3000:80 app

在浏览器访问http://localhost:3000,将显示部署成功的单页面应用

在浏览器控制台查看响应头,将显示nginx版本信息

七、使用Dockerfile指令安装依赖、打包

持续集成工具通常会直接从Git仓库拉取代码,拉取的代码不包含依赖,需要下载依赖

将下载依赖、打包的操作放到Dockerfile指令中,并且使用构建缓存和多阶段构建

将项目根目录的Dockerfile文件(D:\Projects\app-deploy\Dockerfile)的内容修改为

# 继承node:20-alpine镜像,在本次构建中命名为node
# Alpine是一种轻量级的Linux发行版,专为作为容器而设计
# 引入node镜像是为了执行npm命令
FROM node:20-alpine as node

# 改变工作目录为镜像根目录下/temp,如果目录不存在将被自动创建
WORKDIR /temp

# 把项目根目录的package.json复制到镜像根目录下的/temp目录中,再下载依赖
# 在镜像的构建过程中,Dockerfile指令会从上往下执行,每一步的结果都会被缓存起来
# package.json相比上次构建没有变化时,下面两行指令会直接读取缓存,不会再次执行
ADD package.json /temp
RUN npm install --registry https://registry.npmmirror.com

# 把项目根目录的所有文件复制到镜像根目录下的/temp目录中,再执行npm run build打包
ADD . /temp
RUN npm run build


# 继承nginx:alpine镜像,作为部署的最终镜像
FROM nginx:alpine

# 将node镜像/temp/build文件夹下的所有文件都复制到当前镜像的/usr/share/nginx/html文件夹中
COPY --from=node /temp/build /usr/share/nginx/html

# 将node镜像/temp文件夹下的nginx.conf文件复制到当前镜像的/etc/nginx/conf.d文件夹中,命名为default.conf
COPY --from=node /temp/nginx.conf /etc/nginx/conf.d/default.conf

在项目根目录(D:\Projects\app-deploy),执行以下命令构建并启动容器

docker-compose up --build

#up代表创建并启动容器,--build代表每次启动容器前构建镜像

命令行输出如下,显示下载了依赖,下载耗时33.1秒

image

使用Ctrl + C停止运行,再次执行命令构建并启动容器

命令行输出如下,显示读取了缓存

image