# 使用Docker-compose打包整个网站项目一键部署

> 作者/来源: UCloud 运营管理员
> 发布时间: 2022-10-08T06:56:00.000Z
> 分类: 解决方案
> 标签: AI, 数据库, Docker
> 原文链接: http://117.50.162.249:3000/yun/articles/2385

---

# 使用Docker-compose打包整个网站项目一键部署

> 来源: https://www.ucloud.cn/yun/127959.html
> 作者: 社区管理员
> 发布日期: 发布于2022-10-08 14:56

## 一、前言

我们常常见到很多比较棒的开源项目，但在本地安装运行的话就会很复杂，要配置不同的环境，安装不同的依赖，好一点的会用docker直接拉取，或者打包好。

这些无疑都会增加初学者上手的成本，所以这篇文章总结了下目前比较常用的解决方法之一：

**使用docker-compose同时管理多个服务，只需要一行命令`docker compose up -d`，就可以启动一个包含后端项目、前端项目、数据库的完整服务。**

而`docker-compose`作为`docker`容器的编排工具，可以帮助我们实现管理多个`docker`容器。

> 其实整体的过程并不难，但要配置完成，也要很多步骤，这篇文章主要是从实战的角度，将整个过程串起来。涉及的知识点包括：nginx、docker、docker-compose、node、mysql也需要了解下。

适合读下去的朋友：

- 对Docker有基本的了解
- 同时需要部署多个项目
- 需要开源项目或者自建项目的整体部署
- 需要打包部署一整个网站

需要提前准备的：

- Docker安装并启动（演示版本如下）

![image.png](https://ucloud-blog.cn-bj.ufileos.com/articles/127959/images/127959_000.png)

- docker-compose（安装Docker同时会自动安装，如果没有可以自行安装，也很简单）
- 一个前端项目（这里演示使用React SPA）
- 一个后端项目（这里使用Express）

![image.png](https://ucloud-blog.cn-bj.ufileos.com/articles/127959/images/127959_001.png)

如图所示，通过docker-componse.yml文件一次启动不同的容器，然后他们都可以对外提供服务。

## 二、前端项目构建

### 1、前端项目处理

首先我们通过CRA下载一个项目模版，为了可以模拟实际的项目需要，对下载的模版做一些处理，让这个项目可以

- 1、区分当前项目是预发环境还是生产环境
- 2、引入Axios可以请求接口

接着我们打包`yarn build:prod`，打包后的文件夹`build`就是我们要部署的静态资源。

在前面工程化实践过程中提过相关内容，如果有问题可以参考下

- 前端工程化实践 - React项目配置预发环境和生产环境（三）

### 2、拉取Nginx镜像部署

我们通过Docker部署前面打包的静态资源

当前项目的路径是 `/Users/user/Desktop/mine/fronted-demo2/build`

直接运行下面命令行，启动前端服务

```
docker run -d -p 80:80 -v /Users/user/Desktop/mine/fronted-demo2/build:/usr/share/nginx/html --name frontend-test nginx 复制代码
```

![image.png](https://ucloud-blog.cn-bj.ufileos.com/articles/127959/images/127959_002.png)

通过本机80端口访问，发现当前服务是生产环境，并且由于后端服务没有部署，此时数据库拿到的数据为空。

![image.png](https://ucloud-blog.cn-bj.ufileos.com/articles/127959/images/127959_003.png)

测试，我们切换路由，发现页面404了，是因为单页面应用路由在前端，需要nginx转发下，接着我们用项目中的Nginx配置覆盖容器中的配置

### 3、提取Nginx配置到项目中

首先，我们进入上一步的Docker容器，可以看到Nginx的路径。

```
docker exec -it frontend-test /bin/bash 复制代码
```

![image.png](https://ucloud-blog.cn-bj.ufileos.com/articles/127959/images/127959_004.png)

在项目根目录下新建`nginx/default.conf`

```
server {     listen  80;     server_name  localhost;     underscores_in_headers  on;     root /home/frontend;     location / {       try_files $uri $uri/ @router;       index index.html;     }     location @router {       rewrite ^.*$ /index.html last;     } } 复制代码
```

然后通过挂载的方式，启动容器，发现访问正常。

### 4、编写Dockerfile文件

```
FROM nginx WORKDIR /home/frontend COPY build . COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf EXPOSE 80 复制代码
```

在项目根目录下，新建Dockerfile文件，其中包括基础镜像、工作目录、将项目copy到镜像，将Nginx配置文件复制到镜像中。

### 5、构建前端服务镜像并启动

```
docker build -t frontend . docker images docker run -d -p 80:80 --name frontend-v1 frontend 复制代码
```

可以发现前端服务的镜像已经打包完成并启动，打开本地80端口访问，测试完毕可以删除，然后留镜像`frontend`备用。也可以将镜像推送镜像仓库，后面直接通过远程来拉取也可以。

> 主意：如果之前的Docker容器启动，需要先关掉，否则会报端口被占用，如果不删除，就需要修改重新启动容器的名字。

## 三、数据库启动

### 1、拉取并启动数据库、连接数据库

```
docker run -p 3306:3306 --restart=always --privileged=true --name mysql -v /Users/user/Desktop/mysql/data:/var/lib/mysql -v /Users/user/Desktop/mysql/my.cnf:/etc/mysql/my.cnf -e MYSQL_ROOT_PASSWORD="123456" -d mariadb 复制代码
```

一行命令启动Mariadb，这里选择Mariadb是由于我m1的电脑，不支持mysql镜像，所以改成了Mariadb，使用是一样。上面的命令除了启动数据库服务，还设置了数据的一些配置，密码，将数据库的数据放在了本地。

```
[mysqld] skip-name-resolve user=root character-set-server=utf8 default_authentication_plugin=mysql_native_password sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION lower_case_table_names=1 #忽略表名大小写 [client] default-character-set=utf8 [mysql] default-character-set=utf8 复制代码
```

### 2、新建库和表

这里可以进入容器中操作数据库，还可以使用客户端连接数据库

![image.png](https://ucloud-blog.cn-bj.ufileos.com/articles/127959/images/127959_005.png)

## 四、后端项目启动

### 1、下载Express项目模版并连接数据库

这里配置数据库，写好项目接口，确保本地启动服务正常。

### 2、拉起镜像，部署镜像

部署服务，我们选择使用pm2，为了区分生产环境和预发环境，我们在根目录下新建`pm2.config.js`，然后通过传入不同的参数，启动对应的环境

```
module.exports = {   apps : [       {         name: "myapp",         script: "./bin/www",         watch: true,         env: {             "NODE_ENV": "development"         },         env_production: {             "NODE_ENV": "production",         }       }   ] } 复制代码
```

启动预发环境`pm2 start pm2.config.js --env development`

启动生产环境`pm2 start pm2.config.js --env production`

再项目中通过`process.env.NODE_ENV`读取

### 3、编写Dockerfile并构建新的镜像

```
FROM keymetrics/pm2 RUN mkdir -p /home/backend WORKDIR /home/backend COPY ./ /home/backend RUN yarn install ENV NPM_CONFIG_LOGLEVEL warn EXPOSE 9000 CMD ["pm2-runtime", "start", "pm2.config.js", "--env", "production"] 复制代码
```

然后构建镜像`docker build -t backend .`

## 五、docker-compose.yml 配置

截止目前，我们有了三个Docker镜像，分别是前端服务的镜像，后端服务的镜像和数据库的镜像。然后我们编写docker-compose.yml来同时启动这三个服务，并且保证三者的启动顺序

1、编写docker-compose配置文件

新建一个目录，然后再目录下新建`docker-compose.yml`和目录`mysql`，mysql中包含了mysql的数据和日志信息，这样就不用重启服务导致数据库信息丢失

```
version: '3' networks:   app-web:    driver: bridge services:   mysql:     image: mariadb     ports:      - 3306:3306     command: --default-authentication-plugin=mysql_native_password     restart: always     networks:      - app-web     environment:      - TZ=Asia/Shanghai      - MYSQL_USER=root      - MYSQL_ROOT_PASSWORD=123456     volumes:      - ./mysql/data:/var/lib/mysql      - ./mysql/my.cnf:/etc/mysql/my.cnf      - /etc/localtime:/etc/localtime   backend:     image: backend     ports:      - 9000:9000     depends_on:      - mysql     networks:      - app-web   frontend:     image: frontend     ports:      - 80:80     depends_on:      - backend 复制代码
```

看到这个配置不要怕，拆分开，其实很简单，整个配置文件就是一个完整的项目，包括了`mysql`、`backend`、`frontend`，每个部分和配置Dockerfile差不多，增加了depends\_on，很好理解，前置的服务需要提前部署，networks，让不同的容器在相同的网络中运行。

当然这只是提供了最基础的配置，更复杂的配置需要根据使用场景来完善。

2、启动服务

```
docker compose up -d 复制代码
```

-d 是以守护进程的方式运行，通过`docker ps`可以查看当前所有运行中的服务。

![image.png](https://ucloud-blog.cn-bj.ufileos.com/articles/127959/images/127959_006.png)

```
docker compose down 复制代码
```

该语句将会停止当前集群下的所有服务，并删除容器。

到这里，我们的docker-compose整体打包部署一个网站已经完成了，过程中可能存在各种各样的坑，但只要配置报错日志进行查询，就能一一解决。

如果需要重新部署一套，或者发布新版本，只需要更新docker-compose.yml就可以了

## 六、注意点

### 1、mysql配置

数据库和项目的一些信息需要灵活配置，根据自己的需要。

### 2、自动迁移数据库

我们发现，一些新的数据库表，没有进行初始化，导致需要手动处理，在项目中我们可以用脚本去，或者使用一些数据库封装的orm进行自动迁移。

### 3、一些报错信息

![image.png](https://ucloud-blog.cn-bj.ufileos.com/articles/127959/images/127959_007.png)

解决办法，修改mysql配置host为`mysql`

![image.png](https://ucloud-blog.cn-bj.ufileos.com/articles/127959/images/127959_008.png)

- 1、docker拉取镜慢的话，可以考虑国内镜像
- 2、前端、后端项目可以使用任意的语言，只要构架不同的镜像就可以了。

docker查看日志

`docker logs -f --tail 100 containerId`