docker-compose实现容器任务编排

2023-11-14

项目开发中,往往都需要启动多个容器,容器之间又相互依赖,存在着启动的顺序。docker-compose就是可以通过命令控制依次启动容器。
容器编排工具可以帮助我们批量地创建、调度和管理容器,帮助我们解决规模化容器的部署问题。
Docker 三种常用的编排工具:Docker Compose、Docker Swarm 和 Kubernetes。

本文主要是使用 docker-compose 实现react【nginx】、express【node】、mysql【mysql】搭建项目前端通过express访问mysql数据库的功能。

项目目录结构

.
├── 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插件,进行数据的调用。

npx create-react-app react-express
cd react-express
yarn add axios
npm start

调整首页内容

下载好项目,修改src/App.js的内容,实现可以请求后端接口返回的数据。

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构建前端镜像。

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镜像的文件

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文件

server {
  listen 80;
  server_name localhost; # 如 www.baidu.com
  root /usr/share/nginx/html; # 指向打包后的目录

  location / {
    index index.html;
  }
}

生成前端镜像

只需要将编译后的build文件添加到docker镜像中,生成镜像前,先执行下 npm run build

npm run build
docker build -t react-express .

可以看到成功生成react-express镜像。并暴露端口为80,该镜像为后面执行docker-compose做准备。

创建后端项目

首先确保本地安装express;

npm install -g express

使用[express-generator](https://www.expressjs.com.cn/starter/generator.html)生成器生产express-mysql项目

mkdir express-mysql
cd express-mysql
npx express-generator

下载完成后,目录结构如下:

.
├── 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目录结构

  .
  ├── 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设置跨域

// 在路由调用之前设置
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文件

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文件内容

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查询

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文件

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文件

node_modules
*.lock
*.log
yarn-error.log
package-lock.json

在当前目录下,执行docker构建镜像的命令,测试下是否有问题。

docker build -t express-mysql .

初始化数据库

创建sql脚本,在容器启动后给mysql容器初始化数据。【初始化数据有很多其它方案,可以在创建镜像时通过修改配置将初始化数据存入镜像,有兴趣可自行搜索】,在这里只使用简单的手动处理方案,降低认知难度。

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容器

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 <<EOF
use blog;
source /data/compose/init.sql;
quit
EOF

docker-compose编排容器

到目前已经完成了前端、后端、数据库的创建,项目执行依赖多个容器启动,上面的过程非常繁琐,而且容易出现错误。接下来就使用docker-compose可以使用一个命令将3个容器同时启动。

安装[docker-compose](https://docs.docker.com/compose/)

安装完成后查看版本信息

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启动的默认文件

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 文件,执行启动命令

docker-compose up
# 或者 后台启动
docker-compose up -d
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、或者服务器】执行。

#!/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文件。

# 第一阶段,先对前端项目进行编译打包
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文件

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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

docker-compose实现容器任务编排 的相关文章

随机推荐

  • vue 如何实现页面操作之后自动刷新

    近半年时间在接触vue写pc页面 文中内容即在实际的开发过程中遇到的实际问题 需要在app vue文件按照如下代码设置
  • 三分钟训练眼球追踪术,AI就知道你在盯着哪个妹子

    圆栗子 编译整理量子位 出品 公众号 QbitAI 啊 老板的眼神飞过来了 还不快切回工作界面 从前 我们几乎无从躲避来自身后的目光 但现在不一定了 如果有个眼球追踪AI 加上人脸识别 或许就能在被老板盯上的瞬间 进入奋力工作模式 戏是有点
  • c++中的this指针

    c 中的this指针 两个对象的比较 多个对象的比较 this指针存放了对象的地址 它被作为隐藏参数传递给了成员函数 指向调用成员函数的对象 调用者对象 this指针存放了对象的地址 this可以表示对象 两个对象的比较 注意 这里的p3是
  • 555定时器

    一 定义 定时器是一种多用途的数字 模拟混合集成电路 可极方便的构成施密特触发器 单稳态触发器和多谐振荡器 其简化原理图及引脚定义如下所示 3个绿色电阻 电阻值为5K 2个黄色和粉色比较器 1个紫色SR触发器 1个蓝色放电三极管 引脚定义
  • 【满分】【华为OD机试真题2023 JAVA&JS】组装新的数组

    华为OD机试真题 2023年度机试题库全覆盖 刷题指南点这里 组装新的数组 知识点回溯数组 时间限制 1s 空间限制 256MB 限定语言 不限 题目描述 给你一个整数M和数组N N中的元素为连续整数 要求根据N中的元素组装成新的数组R 组
  • PyCharm配置opencv4.5.1

    PyCharm配置opencv4 5 1 一 下载 二 安装 三 环境配置 一 下载 首先我们需要拥有PyCharm软件 opencv4 5 1和pip程序包 下载链接如下 PyCharm https www jetbrains com p
  • (转载)js弹出窗口总结6种弹窗方法

    关闭 父窗口弹出对话框 子窗口直接关闭 this Response Write 关闭 父窗口和子窗口都不弹出对话框 直接关闭 this Response Write 弹出窗口刷新当前页面width 200 height 200菜单 菜单栏
  • 变量和数据类型

    变量概述 变量 它是在程序中最为基本的一种单一数据的存储方式 顾名思义它代表的就是存储的数据可以改变 可以改变的量 值 变量的组成 变量的数据类型 变量名 变量值 数据类型 数值类型 整数类型 1 2 3 0 1 byte 1字节 128
  • 启动MySQL报错ERROR 2003 (HY000) Can‘t connect to MySQL server on ‘localhost‘ (10061)

    这个错误是新手经常会遇到的 本文主要介绍如何修复ERROR 2003 HY000 Can t connect to MySQL server on localhost 10061 1 登录到安装Mysql的主机 打开cmd命令行工具 执行命
  • uniapp SyntaxError: Unexpected token u in JSON at position 0 解决方案

    今天在做页面跳转传值的时候 一直出现下面的报错 后来查看了下文档 说如果你的JSON数据是在上一个页面传值过来的话 这时候在接收数据页解析JSON也会报该错误 因为此时并没有相关的JSON数据从上一个页面传递过来 可以通过判断是否为null
  • Flutter 信息贴

    框架学习 在 Flutter 中构建绘图应用程序 了解如何在 Flutter 中创建绘图应用程序 并探索 Flutter 在 CustomPaint 小部件的帮助下渲染和控制自定义 UI 的能力 在 Flutter 中创建可重用的自定义小部
  • 【IntelliJ IDEA学习之七】maven专题

    版本 IntelliJIDEA2018 1 4 一 maven全局设置 设置Runner 运行VM参数 Xms128m Xmx512m Duser language zh Dfile encoding UTF 8 二 maven项目 参考
  • 手把手教你springboot企业微信开发(一)

    手把手教你springboot企业微信开发 一 1 配置企业号 2 Springboot配置企业号 1 配置企业号 企业号登录 设置 网址是 https work weixin qq com wework admin loginpage w
  • 三天打鱼两天晒网C语言代码

    include
  • mongodb 正则-不区分大小写匹配

    1 正则查询 不区分大小写 i 设置开始字段 结束字段 其中某段匹配任意字段 name regex lslad cn options i 或者 name lslad cn i 2 踩坑记录 java中使用正则查询 name lslad cn
  • 使用 jQuery 创建滚动视图

    jQuery 是一个流行的 JavaScript 库 它简化了 JavaScript 编程 并提供了许多实用的功能和方法 在 jQuery 中 你可以使用 scroll 方法来创建滚动视图 下面是一个详细的教程 帮助你了解如何使用 jQue
  • 再谈Jquery Ajax方法传递到action

    之前写过一篇文章 Jquery Ajax方法传值到action 本文是对该文的补充 假设 controller中的方法是如下 public ActionResult ReadPerson PersonModel model string s
  • 计组(唐第三版)

    目录 前言 讲解问题 1 快速理解基本的电路符号 a 高低电平 b 高电平有效和低电平有效的理解及表示 c 基本的门元件 2 数电小白也能看得懂的74138译码器 c 74138译码器结构功能 c 74138译码器具体结构 3 唐书例4 1
  • 最详细的Python安装+Pycharm安装配置教程,从下载到安装配置

    最详细的Python安装 Pycharm安装配置教程 从下载到安装配置 本章节我们将向大家介绍如何在本地搭建Python开发环境 Python可应用于多平台包括 Linux 和 Mac OS X 你可以通过终端窗口输入 python 命令来
  • docker-compose实现容器任务编排

    项目开发中 往往都需要启动多个容器 容器之间又相互依赖 存在着启动的顺序 docker compose就是可以通过命令控制依次启动容器 容器编排工具可以帮助我们批量地创建 调度和管理容器 帮助我们解决规模化容器的部署问题 Docker 三种