Docker Compose 是一个用于界说和运转多容器 Docker 运用程序的东西。
它答运用户经过一个 YAML 文件来装备运用程序的服务,这个文件称为 docker-compose.yml。
运用 Docker Compose,您能够轻松地办理多个 Docker 容器的部署,包含发动、中止和重启服务,以及查看运转状态等。

基本组成

  • Services:在 docker-compose.yml 文件中,能够界说多个服务,每个服务都将运转在一个或多个容器中。
  • Networks:能够为服务指定网络,以控制容器之间的通讯方式。
  • Volumes:能够界说数据卷,以便在容器之间同享数据或耐久化数据。

创立 Nest 引进 mysql 服务

创立 Nest 项目试试:

nest new docker-compose-test -p npm

装置 tyeporm、mysql2:

npm install @nestjs/typeorm typeorm mysql2

在 mysql workbench 里创立个 database:

CREATE DATABASE `test` DEFAULT CHARACTER SET utf8mb4;

运用 Docker Compose 构建 NestJS 运用并与 MySQL 和 Redis 服务集成

在 AppModule 引进 TypeOrmModule:

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'xxx',
      database: 'test',
      synchronize: true,
      logging: true,
      entities: [],
      poolSize: 10,
      connectorPackage: 'mysql2',
      extra: {
        authPlugin: 'sha256_password',
      },
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

src 目录下创立 test.entity.ts:

import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity()
export class Test {
  @PrimaryGeneratedColumn()
  id: number;
  @Column()
  name: string;
  @Column()
  email: string;
}

在 entities 里注册下:

运用 Docker Compose 构建 NestJS 运用并与 MySQL 和 Redis 服务集成

发动 Nest 服务:

npm run start:dev

运用 Docker Compose 构建 NestJS 运用并与 MySQL 和 Redis 服务集成

mysql 服务没问题。

引进 redis 服务

npm install redis

AppModule 增加一个 redis:

运用 Docker Compose 构建 NestJS 运用并与 MySQL 和 Redis 服务集成

{
  provide: 'REDIS_CLIENT',
  async useFactory() {
    const client = createClient({
      socket: {
        host: 'localhost',
        port: 6379,
      },
    });
    await client.connect();
    return client;
  },
},

在 AppControll 里注入下:

运用 Docker Compose 构建 NestJS 运用并与 MySQL 和 Redis 服务集成

然后拜访下 http://localhost:3000 后。
服务端打印了 redis 里的 key:
运用 Docker Compose 构建 NestJS 运用并与 MySQL 和 Redis 服务集成

这就阐明 redis 服务也衔接成功了。

没有 docker compose

假设咱们 nest 服务开发完了,想部署,那就要写这样的 dockerfile:

# Step 1: 运用带有 Node.js 的基础镜像
FROM node:18-alpine as builder
# 设置作业目录
WORKDIR /usr/src/app
# 仿制 package.json 和 package-lock.json(假如可用)
COPY package*.json ./
# 装置项目依靠
RUN npm install --only=production
# 装置 nest CLI 东西(保证它作为项目依靠被装置)  
RUN npm install @nestjs/cli -g
# 仿制一切文件到容器中
COPY . .
# 构建运用程序
RUN npm run build
# Step 2: 运转时运用更精简的基础镜像
FROM node:18-alpine
# 创立 runc 的符号链接
RUN ln -s /sbin/runc /usr/bin/runc
WORKDIR /usr/src/app
# 从 builder 阶段仿制构建好的文件
COPY --from=builder /usr/src/app/dist ./dist
COPY --from=builder /usr/src/app/node_modules ./node_modules
# 露出 3000 端口
EXPOSE 3000
# 运转 Nest.js 运用程序
CMD ["node", "dist/main"]

由于咱们项目依靠 mysql,redis,所以咱们要先运转 mysql、redis 镜像,最后才能运转 nest 镜像。
咱们运转之后还会报错:

运用 Docker Compose 构建 NestJS 运用并与 MySQL 和 Redis 服务集成

说是 127.0.0.1 的 6379 端口连不上。
注意 nest 容器里需要运用宿主机 ip 来拜访 mysql、redis 服务,所以咱们在 nest 运用里面要把 mysql 和 redis 的 host 全改写宿主机 ip。
终端输入 ifconfig,在 en0 找到自己的 ip。
之后 dockerfile build 一个 nest 镜像,别离按次序运转 mysql、redis 和 nest 镜像即可。

引进 docker compose

**编写 docker-compose.yml 文件:**根目录增加一个 docker-compose.yml,界说服务、网络和数据卷等:

version: '1.0'
# 界说服务,即需要运转的容器集合  
services:  
  # 界说一个名为'nest-app'的服务  
  nest-app:  
    # 构建装备,指定Dockerfile的途径和上下文  
    build:  
      # 指定Docker构建上下文的途径,通常是Dockerfile所在的目录  
      context: ./  
      # 指定Dockerfile的途径,相对于构建上下文  
      dockerfile: ./Dockerfile  
    # 界说该服务所依靠的其他服务,它们将按照依靠次序发动  
    depends_on:  
      # 依靠名为'mysql-container'的服务  
      - mysql-container  
      # 依靠名为'redis-container'的服务  
      - redis-container  
    # 端口映射,将宿主机的3000端口映射到容器的3000端口  
    ports:  
      - '3000:3000'
  # 界说一个名为'mysql-container'的服务,运用mysql镜像  
  mysql-container:  
    # 指定运用mysql官方Docker镜像  
    image: mysql  
    # 端口映射,将宿主机的3306端口映射到容器的3306端口  
    ports:  
      - '3306:3306'  
    # 数据卷装备,用于耐久化存储  
    volumes:  
      # 将宿主机的/Users/yunmu/Desktop/mysql目录映射到容器的/var/lib/mysql目录  
      - /Users/yunmu/Desktop/mysql:/var/lib/mysql
    environment:
      MYSQL_DATABASE: test
      MYSQL_ROOT_PASSWORD: xxx
  # 界说一个名为'redis-container'的服务,运用redis镜像  
  redis-container:  
    # 指定运用redis官方Docker镜像  
    image: redis  
    # 端口映射,将宿主机的6379端口映射到容器的6379端口  
    ports:  
      - '6379:6379'  
    # 数据卷装备,用于耐久化存储  
    volumes:  
      # 将宿主机的/Users/yunmu/Desktop/redis目录映射到容器的/data目录  
      - /Users/yunmu/Desktop/redis:/data

每个 services 都是一个 docker 容器,名字随意指定。

发动服务 :运转以下指令来发动一切界说的服务:

docker-compose up

它会把一切容器的日志一起输出,先跑的 mysql、redis,再跑的 nest。
也能够运转这个指令:

docker-compose up -d --build --force-recreate
  • -d:Detached mode,意味着 Docker Compose 会在后台运转容器。
  • -build:在发动服务之前强制重构建服务关联的镜像。
  • --force-recreate:即使容器的装备没有改动,也强制重新创立容器。

运用 Docker Compose 构建 NestJS 运用并与 MySQL 和 Redis 服务集成

成功创立。

浏览器拜访下 http://localhost:3000/

运用 Docker Compose 构建 NestJS 运用并与 MySQL 和 Redis 服务集成

运用 Docker Compose 构建 NestJS 运用并与 MySQL 和 Redis 服务集成

nest 容器内打印了 redis 的 key。

中止移除 Docker Compose 发动的容器:

docker-compose down

假如还想移除对应的镜像,请运用:

docker-compose down --rmi all

桥接网络

Docker 桥接网络是一种网络形式,答应容器在同一个宿主机上进行通讯,一起与宿主机以及其他未衔接到该桥接网络的容器阻隔。
在 Docker 桥接网络中,每个容器都会被分配一个独立的IP地址,并且这些IP地址都是与宿主机不同的。
Docker 经过桥接器(bridge)将这些容器衔接起来,构成一个虚拟的网络环境。
容器之间能够经过这个网络环境进行通讯,而宿主机也能够经过桥接器与容器进行通讯。

Docker桥接网络适用于在同一个宿主机上运转的容器之间的通讯。假如需要在不同宿主机上的容器之间进行通讯,则能够运用Docker的覆盖网络(overlay network)。

当发动一个Docker容器时,假如没有指定网络形式,那么默许会运用桥接网络。能够经过Docker指令或Docker Compose文件来装备容器的网络形式。
经过 docker network 来创立叫桥接网络:

docker network create common-network

运用 Docker Compose 构建 NestJS 运用并与 MySQL 和 Redis 服务集成

运用 Docker Compose 构建 NestJS 运用并与 MySQL 和 Redis 服务集成

经过 networks 指定创立的 common-network 桥接网络,网络驱动程序指定为 bridge。
其实咱们一向用的网络驱动程序都是 bridge,它的含义是容器的网络和宿主机网络是阻隔开的,可是能够做端口映射。比方 -p 3000:3000、-p 3306:3306 这样。

修改 AppModule 的代码,改成用容器名来拜访:

运用 Docker Compose 构建 NestJS 运用并与 MySQL 和 Redis 服务集成

先删除之前的容器镜像:

docker-compose down --rmi all

运转 compose:

运用 Docker Compose 构建 NestJS 运用并与 MySQL 和 Redis 服务集成

运用 Docker Compose 构建 NestJS 运用并与 MySQL 和 Redis 服务集成

成功运转。

其实不指定 networks 也能够,docker-compose 会创立个默许的:

运用 Docker Compose 构建 NestJS 运用并与 MySQL 和 Redis 服务集成

运转 docker-compose up , 你会发现它创立了一个默许的 network:
运用 Docker Compose 构建 NestJS 运用并与 MySQL 和 Redis 服务集成

所以,不手动指定 networks,也是能够用桥接网络的。
咱们假如不必 docker compose,能够在 docker run 的时分指定 –network,这样 3 个容器经过容器名也能互相拜访。
比方:

docker run -d --network common-network -v /Users/yunmu/Desktop/mysql:/var/lib/mysql --name mysql-container mysql
docker run -d --network common-network -v /Users/yunmu/Desktop/redis:/data --name redis-container redis
docker run -d --network common-network -p 3000:3000 --name nest-container nest-image

其实本质就是对 Network Namespace 的处理,本来是 3 个独立的 Namespace,当指定了 network 桥接网络,就能够在自己 Namespace 下拜访别的 Namespace 了。