项目开发中,往往都需要启动多个容器,容器之间又相互依赖,存在着启动的顺序。docker-compose就是可以通过命令控制依次启动容器。
容器编排工具可以帮助我们批量地创建、调度和管理容器,帮助我们解决规模化容器的部署问题。
Docker 三种常用的编排工具:Docker Compose、Docker Swarm 和 Kubernetes。
本文主要是使用 docker-compose 实现react【nginx】、express【node】、mysql【mysql】搭建项目前端通过express访问mysql数据库的功能。
项目目录结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
. ├── docker-compose.yml ├── express-mysql │ ├── app.js │ ├── bin │ ├── Dockerfile │ ├── node_modules │ ├── package.json │ ├── public │ ├── routes │ ├── src │ ├── views │ └── yarn.lock ├── init.sql ├── react-express │ ├── Dockerfile │ ├── Dockerfile.build │ ├── node_modules │ ├── package.json │ ├── public │ ├── react-express.conf │ ├── src │ └── yarn.lock └── start.sh |
创建前端项目
使用 [create-react-app](https://create-react-app.bootcss.com/)
搭建前端项目,并安装axios插件,进行数据的调用。
1
2
3
4
|
npx create-react-app react-express cd react-express yarn add axios npm start |
调整首页内容
下载好项目,修改src/App.js
的内容,实现可以请求后端接口返回的数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
import "./App.css" ; import { useState, useEffect } from "react" ; import axios from "axios" ; function App() { const [user, setUser] = useState([]); useEffect(() => { axios.get( "http://localhost:8088/sql" ).then((res) => { setUser(res.data); }); }, []); return ( <div className= "App" > <header className= "App-header" > {user.map((u, i) => ( <p key={i}> {u.username}</p> ))} </header> </div> ); } export default App; |
添加Dockerfile文件
使用Dockerfile构建前端镜像。
1
2
3
4
5
6
7
|
FROM nginx COPY . /build /usr/share/nginx/html COPY . /react-express .conf /etc/nginx/conf .d WORKDIR /usr/share/nginx/html EXPOSE 80 # 启动ngnix CMD [ "nginx" , "-g" , "daemon off;" ] |
添加.dockerignore
文件,排除不需要打包到docker镜像的文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
node_modules # testing /coverage # misc .DS_Store .env.local .env.development.local .env.test.local .env.production.local npm-debug.log* yarn-debug.log* yarn-error.log* |
添加nginx配置文件
添加react-express.conf
文件
1
2
3
4
5
6
7
8
9
|
server { listen 80; server_name localhost; # 如 www.baidu.com root /usr/share/nginx/html ; # 指向打包后的目录 location / { index index.html; } } |
生成前端镜像
只需要将编译后的build
文件添加到docker镜像中,生成镜像前,先执行下 npm run build
。
1
2
|
npm run build docker build -t react-express . |
可以看到成功生成react-express
镜像。并暴露端口为80,该镜像为后面执行docker-compose做准备。
创建后端项目
首先确保本地安装express;
1
|
npm install -g express |
使用[express-generator](https://www.expressjs.com.cn/starter/generator.html)
生成器生产express-mysql
项目
1
2
3
|
mkdir express-mysql cd express-mysql npx express-generator |
下载完成后,目录结构如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
. ├── Dockerfile ├── app.js ├── bin │ └── www ├── package.json ├── public │ ├── images │ ├── javascripts │ └── stylesheets ├── routes │ ├── index.js │ └── users.js ├── views │ ├── error.jade │ ├── index.jade │ └── layout.jade └── yarn.lock |
为了连接mysql数据库,新增src目录结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
. ├── Dockerfile ├── app.js ├── bin │ └── www ├── package.json ├── public │ ├── images │ ├── javascripts │ └── stylesheets ├── routes │ ├── index.js │ └── users.js + ├── src + │ ├── config.js + │ ├── db.js ├── views │ ├── error.jade │ ├── index.jade │ └── layout.jade └── yarn.lock |
修改app.js设置跨域
1
2
3
4
5
6
7
8
9
10
11
|
// 在路由调用之前设置 app.all( '*' , function (req, res, next) { res.header( "Access-Control-Allow-Origin" , "*" ); res.header( "Access-Control-Allow-Headers" , "X-Requested-With" ); res.header( "Access-Control-Allow-Methods" , "PUT,POST,GET,DELETE,OPTIONS" ); res.header( "X-Powered-By" , ' 3.2.1' ) res.header( "Content-Type" , "application/json;charset=utf-8" ); next(); }); // ... |
连接mysql的配置
src/config.js
文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
module.exports = { port: 3333, // express 服务启动端口 /* 数据库相关配置 */ db: { host: 'localhost' , // 主机名 port: 8808, // MySQL 默认端口为 3306 user: 'root' , // 使用 root 用户登入 MySQL password: '123456' , // MySQL 密码,用你自己的 database: 'blog' , // 使用数据库 useConnectionPooling: true , // 使用连接池进行连接,否则过一会node连接的mysql就会断开,出现错误 connectionLimit: 50, queueLimit: 0, waitForConnection: true } } |
src/db.js文件内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
const mysql = require( "mysql" ); // 获取数据库配置信息 const config = require( "./config" ).db; //创建一个mysql连接对象 let connection; function handleError(err) { if (err) { // 如果是连接断开,自动重新连接 if (err.code === "PROTOCOL_CONNECTION_LOST" ) { connect(); } else { console.error(err.stack || err); } } } // 连接数据库 function connect() { console.log( "连接数据库 connect" ); //创建一个mysql连接对象 connection = mysql.createPool(config); connection.getConnection(handleError); connection.on( "error" , handleError); } connect(); module.exports = connection; |
进行sql查询
在routes/index.js
下设置sql查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
var express = require( "express" ); var router = express.Router(); const connection = require( "../src/db" ); /* GET home page. */ router.get( "/sql" , function (req, res, next) { /* 使用 connection.query 来执行 sql 语句 */ // 第一个参数为 sql 语句,可以透过 js 自由组合 // 第二个参数为回调函数,err 表示查询异常、第二个参数则为查询结果(这里的查询结果为多个用户行) connection.query( "select username from user" , (err, users) => { if (err) { res.send( "query error" + err); } else { // 将 MySQL 查询结果作为路由返回值 res.send(users); } }); }); module.exports = router; |
构建后端镜像
新建Dockerfile
文件
1
2
3
4
5
6
|
FROM node:16.11.0 COPY ./ /app WORKDIR /app RUN npm config set registry https: //registry .npm.taobao.org && npm install EXPOSE 3000 CMD npm start |
新建.dockerignore
文件
1
2
3
4
5
|
node_modules *.lock *.log yarn-error.log package-lock.json |
在当前目录下,执行docker构建镜像的命令,测试下是否有问题。
1
|
docker build -t express-mysql . |
初始化数据库
创建sql脚本,在容器启动后给mysql容器初始化数据。【初始化数据有很多其它方案,可以在创建镜像时通过修改配置将初始化数据存入镜像,有兴趣可自行搜索】,在这里只使用简单的手动处理方案,降低认知难度。
1
2
3
4
5
6
7
8
9
10
|
DROP TABLE IF EXISTS `user`; create table user ( id bigint auto_increment primary key, username varchar(255) not null ) collate = utf8mb4_unicode_ci; INSERT INTO blog.user ( id , username) VALUES (1, 'admin' ); INSERT INTO blog.user ( id , username) VALUES (2, 'docker' ); |
创建 mysql容器
1
2
3
4
5
6
|
docker run -d --name mysql-user -p 8087:3306 \ - v /data/docker-data/docker_mysql/conf : /etc/mysql/conf .d \ - v /data/docker-data/docker_mysql/logs : /logs \ - v /data/docker-data/docker_mysql/data : /var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=123456 \ mysql:5.7 |
登录mysql并初始化数据
mysql -hlocalhost -P8087 -uroot -p123456 <<EOFuse blog;source /data/compose/init.sql;quitEOF
1
2
3
4
5
|
mysql -hlocalhost -P8087 -uroot -p123456 <<EOF use blog; source /data/compose/init.sql; quit EOF |
docker-compose编排容器
到目前已经完成了前端、后端、数据库的创建,项目执行依赖多个容器启动,上面的过程非常繁琐,而且容易出现错误。接下来就使用docker-compose
可以使用一个命令将3个容器同时启动。
安装[docker-compose](https://docs.docker.com/compose/)
安装完成后查看版本信息
1
2
3
4
5
6
|
docker-compose version --- docker-compose version 1.29.2, build unknown docker-py version: 5.0.3 CPython version: 3.6.8 OpenSSL version: OpenSSL 1.0.2k-fips 26 Jan 2017 |
新建yml文件
docker-compose.yml是docker-compose启动的默认文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
version: "3.1" services: react: build: context: "./react-express" dockerfile: Dockerfile depends_on: - express ports: - "8086:80" mysql: image: mysql:5.7 container_name: mysql5 ports: - "8087:3306" environment: MYSQL_ROOT_PASSWORD: 123456 MYSQL_DATABASE: "blog" volumes: - "/data/docker-data/docker_mysql/conf:/etc/mysql/conf.d" - "/data/docker-data/docker_mysql/logs:/logs" - "/data/docker-data/docker_mysql/data:/var/lib/mysql" express: build: context: "./express-mysql" dockerfile: Dockerfile ports: - "8088:3000" depends_on: - mysql |
设置完成 yml 文件,执行启动命令
1
2
3
|
docker-compose up # 或者 后台启动 docker-compose up -d |
1
2
3
4
5
6
|
docker-compose ps Name Command State Ports ---------------------------------------------------------------------------------------------------------------- compose_express_1 docker-entrypoint.sh /bin/ ... Up 0.0.0.0:8088->3000 /tcp ,:::8088->3000 /tcp compose_react_1 /docker-entrypoint .sh ngin ... Up 0.0.0.0:8086->80 /tcp ,:::8086->80 /tcp mysql5 docker-entrypoint.sh mysqld Up 0.0.0.0:8087->3306 /tcp ,:::8087->3306 /tcp , 33060 /tcp |
一个命令就可以启动多个容器,并且组织好容器之间的依赖关系。
继续优化
创建前端镜像存在的问题.
每次打包前端镜像时,需要先完成 build 的阶段,也就是前端编译的过程。该过程其实也可以自动处理。
方案1:使用shell执行
在项目目录下创建 start.sh
文件, 将前端编译的过程放到外部node环境【jenkins、或者服务器】执行。
1
2
3
4
5
6
7
8
9
10
|
#!/bin/bash cd react-express yarn run build cd .. docker-compose up -d mysql -hlocalhost -P8087 -uroot -p123456 <<EOF use blog; source . /init .sql; quit EOF |
方案2:采用镜像多阶段构建
思路:将编译过程放到node环境中,打包出来build目录,然后将build目录拷贝到后边镜像内。
新建一个Dockerfile.build文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# 第一阶段,先对前端项目进行编译打包 FROM node:16.11.0 AS nodeapp COPY ./ /app WORKDIR /app RUN yarn && yarn build #多阶段构建,最终会以最后的镜像作为基础镜像 # 第二阶段,将打包的数据拷贝到后边镜像内,并创建nginx镜像 FROM nginx COPY --from=nodeapp /app/build /usr/share/nginx/html COPY . /react-express .conf /etc/nginx/conf .d WORKDIR /usr/share/nginx/html EXPOSE 80 # 启动ngnix CMD [ "nginx" , "-g" , "daemon off;" ] |
然后同步修改下docker-compose.yml
文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
version: "3.1" services: react: build: context: "./react-express" dockerfile: Dockerfile.build depends_on: - express ports: - "8086:80" mysql: image: mysql:5.7 container_name: mysql5 ports: - "8087:3306" environment: MYSQL_ROOT_PASSWORD: 123456 MYSQL_DATABASE: "blog" volumes: - "/data/docker-data/docker_mysql/conf:/etc/mysql/conf.d" - "/data/docker-data/docker_mysql/logs:/logs" - "/data/docker-data/docker_mysql/data:/var/lib/mysql" express: build: context: "./express-mysql" dockerfile: Dockerfile ports: - "8088:3000" depends_on: - mysql |
到此这篇关于docker-compose实现容器任务编排的方法步骤的文章就介绍到这了,更多相关docker-compose 容器任务编排内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://blog.csdn.net/shenshuai89/article/details/127842097