使用Docker Compose设置本地开发环境

Docker Compose 是一个方便的工具,可以帮助您创建和运行使用多个容器的应用程序。它通过让您在一个文件中定义所需的一切,使设置和部署复杂应用程序的过程更加简单。使用 Docker Compose,您可以一起管理所有容器,并轻松控制它们的交互方式。

在这篇博客中,我们将探讨使用Docker Compose的好处,以及它如何帮助您简化基于Docker的应用程序开发和部署。我们将介绍Docker Compose的基础知识,包括如何在Compose文件中定义服务、网络和卷,以及如何使用Docker Compose启动、停止和管理应用程序堆栈。

docker-compose是什么?

Docker Compose 是一个工具,可以通过单个命令快速启动多个容器。使用 Docker Compose,我们可以创建一个 YAML 文件,定义如何创建多个服务(容器),并使用单个命令启动或关闭它们。

安装:

  1. 如何在Linux上安装docker-compose:

如何在Windows/Mac上安装docker-compose:

对于Windows/Mac,Docker Compose已经与Docker Desktop预装,因此您需要安装Windows/Mac的Docker Desktop才能使用Docker Compose。

示例的docker-compose文件:

json 复制代码
version: "3.8"
services:
  service-1:
    build: 
      context: pathOfCodeFolder
      dockerfile: dockerFile name
    image: dockerImageName
    ports:
      - "hostPort:ContainerPort"
    entrypoint: ["/bin/sh","entrypoint.sh"]
    command: npm run dev
    restart: always
    container name: contianer-front-end
    environment: 
      key: value
    env_file:
      - pathOfEnvFile
    networks:
      - networkName
    volumes: # this is called as volume binding
        - volumeName:ContainerPath
    volumes: # this is called as host binding
      - hostPath:containerPath
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 64M
    depends_on:
      - serviceName
  
  
  service-2:
    ...
networks:
  network_name:
    driver: <driverType>   
voulmes:
  volumeName

Docker Compose 文件参数概览:

  • 版本:这指定了docker-compose文件的版本。
  • 借助Docker Compose中的服务,我们可以创建多个服务,如前端、后端和数据库服务等。
  • 使用Docker Compose中的 build 关键字,我们可以为服务创建一个镜像。 context 关键字用于指定Dockerfile所在的目录。此外,使用 dockerfile 关键字,我们可以指定Dockerfile使用的自定义名称。
  • 如果我们想要使用来自Docker仓库(如DockerHub)的预构建镜像,我们只需要在Docker Compose文件中指定镜像名称。

当我们在Docker Compose文件中同时使用 buildimage 关键字时,镜像将使用 build 关键字中指定的上下文进行构建, image 关键字将为新镜像分配一个名称。然后,这个新镜像将在 docker images 命令下列出。

  • 通过端口暴露的帮助,我们可以从本地主机访问运行在容器中的站点。在左边,我们定义主机端口,在右边,我们定义容器端口。例如,如果一个 Node 容器正在 4000 端口运行,并且我们想要从主机机器上的 80 端口访问它,我们可以在 compose 文件中像这样定义端口:(hostPort:containerPort)。
  • 入口点和命令:

在Docker Compose中, entrypointcommand 之间存在差异。当为一个服务定义了 entrypoint 时,它是无法被覆盖的,我们可以使用 entrypoint 来运行可执行命令,比如迁移和填充。另一方面, command 是可以被覆盖的,我们可以在单个服务中指定多个要运行的命令。以下是一个示例代码片段。

cmd 复制代码
command: >
    bash -c "python manage.py migrate
    && python manage.py runserver 0.0.0.0:8000"
  • 在Docker Compose中,我们可以使用 environment 关键字在运行时指定环境变量,就像上面的示例代码片段中所示。
  • environment_file: 在需要指定包含环境变量的整个文件的情况下,我们可以使用上面示例代码片段中所示的 environment_file 关键字。
  • container_name: Docker Compose 中的 container_name 关键字允许我们为容器指定自定义名称。
  • 重新启动策略:在Docker Compose中,对于每个服务都要指定一个重新启动策略是很重要的。例如,如果重新启动策略设置为"always",那么当主机机器重新启动时,Docker容器将会自动重新启动。如果没有指定,则容器在主机重新启动或重启时不会重新启动。关于重新启动策略的更多信息可以在Docker文档中找到。
  • depends_on: 当一个服务依赖于另一个服务时,可以使用 depends_on 关键字。例如,假设后端容器需要数据库容器在其启动之前运行。在这种情况下,我们可以在后端服务中使用 depends_on ,以便在后端容器启动之前创建数据库容器。
  • 网络:如上面的代码片段所示,我们可以在Docker Compose中创建网络并将其附加到特定的服务。可用的网络类型包括桥接、主机和覆盖网络。有关Docker网络的更多信息,请访问官方Docker文档。
  • 我们需要在需要数据持久存储时使用卷挂载,这样数据就可以在容器停止或移除后重新启动。
  1. 在Docker Compose中,我们可以使用基于主机的挂载来实现在不重新启动容器的情况下立即对网站进行代码更改。例如,如果我们正在运行前端和后端服务,我们可以在主机机器上进行代码更改,借助基于主机的挂载,这些更改将立即反映在容器中。
cmd 复制代码
volumes:
      - 'hostPathOfCode:containerDirName'

卷挂载:为了持久化数据库容器的卷,我们可以创建一个卷并将其附加到数据库服务,如下面的代码片段所示。

cmd 复制代码
volumes:
      - 'backend-db:containerDirName'

volumes:
  backend-db:

Docker 的资源限制:

如果在Docker Compose中没有为容器设置资源限制,它将使用主机PC的全部RAM和CPU限制。要检查容器的RAM和CPU使用情况,可以使用docker stats命令。

下面的图片显示了一个没有设置RAM和CPU限制的容器:

没有设置内存和CPU限制的容器:

设置了RAM和CPU限制之后的容器:

cmd 复制代码
deploy:
      resources:
        limits:
          cpus: '2'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 64M

如上所示,我已经在每个容器上设置了512MB的限制。这意味着每个容器的最大内存使用量为512MB。

通过限制每个容器的RAM和CPU,我们可以保护主机的RAM和CPU免受过度利用。

让我们使用docker-compose来设置本地开发环境

如何创建一个Docker Compose文件来运行前端、后端和数据库容器。

cmd 复制代码
version: '3.8'

services:
  postgres:
    image: postgres:latest
    container_name: postgres
    ports: 
      - '5432:5432'
    environment:
      POSTGRES_PASSWORD: helloworld
      POSTGRES_USER: test
      POSTGRES_DB: testdb
    volumes:
      - 'backend-db:/var/lib/postgresql/data'
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 64M
    networks:
      - application
    
  frontend:
    depends_on:
      - backend
    build:
      context: ./boilerplate_next/
      dockerfile: Dockerfile
    image: compose_next 
    container_name: frontend
    ports:
      - '3000:3000'
    volumes:
      - './boilerplate_next:/app'
      - '/app/node_modules'
      - '/app/.next'
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 64M
    networks:
      - application

  backend:
    depends_on:
      - postgres
    build:
      context: ./server-js/
      dockerfile: Dockerfile
    image: compose_node 
    container_name: backend
    volumes:
      - './server-js/:/app'
    ports:
      - '8000:8000'
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 64M
    networks:
      - application
      
networks:
  application:
    driver: bridge
volumes:
  backend-db:

我们需要挂载前端的 node_modules 和 .next 文件夹,因为在构建过程中卷没有被挂载。

Dockerfiles:

前端Dockerfile:

dockerfile 复制代码
FROM node:18.16.0-slim 

WORKDIR /app

COPY package.json .

RUN npm install

COPY . .

EXPOSE 3000

RUN npm run build

CMD ["npm","run","start"]

后端Dockerfile:

dockerfile 复制代码
FROM node:16.15.0-alpine

WORKDIR /app

COPY package.json ./

RUN npm i

COPY . ./

EXPOSE 8000

RUN ["chmod","+x","entrypoint.sh"]


Entrypoint.sh

npm install 

npx sequelize db:migrate --config config/config.js

npx sequelize db:seed --seed ./backend/seeders/20220630094531-create-user.js

npm run dev

对于Postgres数据库,我们使用了预先构建的Docker镜像作为postgres:latest

  1. 在这里,我们需要运行三个服务:前端、后端和Postgres,因此按照上面所示创建三个服务。
  2. 最佳实践:在每个服务中,我们应该定义访问该服务的端口,指定是构建还是使用现有的镜像,挂载卷以持久化数据并将代码从主机挂载到容器中,设置资源限制,应用网络,并分配容器名称。
  3. 查看容器日志:docker logs
  4. 运行compose文件:docker-compose up -d(-d用于在后台运行容器)
  5. 关闭并删除文件:docker-compose down(停止和删除容器、网络,不会删除卷;要删除卷,请使用 -v)。

这是上述代码的输出。

运行:docker-compose up

在docker-compose中定义的3000端口访问前端

请注意:要将后端容器与数据库容器连接起来,需要在后端容器的环境变量中使用服务名称作为主机名。

热重载:
重新加载应用程序而不重新启动容器

前端:在不重启容器的情况下,我们需要遵循两个步骤来在主机代码中更改代码并重新加载应用程序。

  1. 我们需要在compose文件中挂载一个卷。
  2. 使用开发命令如 npm run dev

后端:在主机代码发生更改时更新容器化应用程序而无需重新构建它,我们需要像上面的代码中所示那样挂载一个卷,并将 nodemon 功能添加到 package.json 文件中。

例如,如果您对前端代码进行更改,Docker Compose可以自动在运行的应用程序中反映这些更改,而无需您重新创建容器。

这里,我修改了一行代码。

在不重新启动容器的情况下,更改会反映在运行中的应用程序中

故障排除命令:

  • 要删除所有未附加到任何容器的Docker镜像: `` docker rmi -f docker imaages -aq
  • 要删除所有已停止的Docker容器: ``docker rm `docker ps -aq```
  • 进入容器内: docker exec -it <contianerid or name>
  • 显示Docker的RAM和CPU使用情况: docker stats
  • 检查容器的日志: docker logs <container_id_or_name>
  • 如果图像不存在,则构建图像并启动容器: docker-compose up
  • 在启动容器之前构建镜像: docker-compose up --build
  • 停止容器并删除由up创建的容器、网络、卷和镜像: docker-compose down

默认情况下 docker-compose down 不会删除,要删除请使用 docker-compose down -v

收尾工作👋

通过在本地环境中设置应用程序,我们可以调试与前端、后端和数据库相关的问题。这使我们能够快速识别和解决开发过程中可能出现的任何问题。

使用Docker Compose 的另一个优势是它能够在本地复制生产环境。通过在Docker Compose 配置文件中定义生产环境,开发人员可以轻松地在本地机器上重新创建它,消除了对昂贵硬件和基础设施的需求。这导致更快的开发周期和更准确的测试,从而产生更稳定可靠的应用程序。

相关推荐
全能全知者7 分钟前
docker快速安装与配置mongoDB
mongodb·docker·容器
阿尔帕兹2 小时前
构建 HTTP 服务端与 Docker 镜像:从开发到测试
网络协议·http·docker
ZHOU西口4 小时前
微服务实战系列之玩转Docker(十八)
分布式·docker·云原生·架构·数据安全·etcd·rbac
景天科技苑6 小时前
【云原生开发】K8S多集群资源管理平台架构设计
云原生·容器·kubernetes·k8s·云原生开发·k8s管理系统
wclass-zhengge7 小时前
K8S篇(基本介绍)
云原生·容器·kubernetes
颜淡慕潇7 小时前
【K8S问题系列 |1 】Kubernetes 中 NodePort 类型的 Service 无法访问【已解决】
后端·云原生·容器·kubernetes·问题解决
川石课堂软件测试9 小时前
性能测试|docker容器下搭建JMeter+Grafana+Influxdb监控可视化平台
运维·javascript·深度学习·jmeter·docker·容器·grafana
昌sit!15 小时前
K8S node节点没有相应的pod镜像运行故障处理办法
云原生·容器·kubernetes
追风林16 小时前
mac 本地docker-mysql主从复制部署
mysql·macos·docker
A ?Charis18 小时前
Gitlab-runner running on Kubernetes - hostAliases
容器·kubernetes·gitlab