博客 / 詳情

返回

使用DockerCompose部署服務

由於格式或圖片解析問題,為了更好的閲讀體驗,可前往 閲讀原文

以前我們總是用命令管理每個容器的啓動、停止等等,若有多個容器時可能還存在啓動優先級的問題,那就要等到指定的容器啓動後再去啓動另一個容器,對於整體的應用服務管理極其不方便,簡單的docker run命令更適合初學者或者調試使用, docker提供docker compose來解決多容器部署。

Docker Compose是Docker官方提供的一個工具,它允許用户通過配置文件定義和運行多個 Docker 容器,以便更輕鬆地管理 Docker 應用程序的部署和運行。Docker Compose 可以讓用户在單個主機上運行多個容器,也可以在多個主機上運行同一組容器,並且可以實現容器之間的相互通信和協作。

掃碼關注攻粽號,查看更多優質文章

優勢

相比啓動單個容器,使用docker compose有以下優勢:

  • 簡化多容器應用部署: Docker Compose 可以將多個容器的部署、啓動、停止、刪除等操作集成到一起,以便簡化多容器應用的部署和管理。
  • 統一配置管理: Docker Compose 允許用户使用 YAML 文件定義容器的配置,從而實現容器的統一管理。這使得在多容器應用中對於環境變量、網絡設置、端口映射等配置的管理更加方便和統一。
  • 容器之間的通信: Docker Compose 允許用户自定義容器之間通信的網絡,容器之間可以直接通信,方便了應用程序的開發和部署。
  • 可重複性和可移植性: 使用 Docker Compose 可以將應用程序的部署過程進行標準化,降低了部署過程中的錯誤率。同時,Docker Compose 配置文件可以在不同的環境中使用,從而實現應用程序的可移植性。
  • 管理多個環境: Docker Compose 可以對不同的環境進行管理,比如開發環境、測試環境和生產環境,從而方便了應用程序的開發和測試。

初識DockerCompose

Docker Compose 配置文件是一個 YAML 格式的文件,用於定義多個 Docker 容器的配置和關係。下面是一個簡單的 Docker Compose 配置文件示例:

version: '3'
services:
  web:
    build:
        context: .
        dockerfile: Dockerfile.web
    ports:
      - "8080:80"
    depends_on:
        - redis
  redis:
    image: "redis:alpine"

在這個示例配置文件中,version 字段指定了 Docker Compose 的版本號,services 字段用於定義多個 Docker 容器。在 services 字段中,每個容器都是一個子字段,其鍵名是容器的名稱,其值是一個包含容器配置的鍵值對。

在示例配置文件中,定義了兩個容器 web 和 redis,其中:

  1. web 容器使用本地 Dockerfile.web 配置文件構建鏡像,將容器的 80 端口映射到主機的 8080 端口,<u>其依賴redis的啓動後才會啓動自己</u>。
  2. redis 容器使用 Redis 官方鏡像,並使用 Alpine 版本,沒有指定其他特殊的配置。

從以上可以看出docker compose是將整個應用的所有容器全部寫在了同一個配置文件中,其也會自動管理容器的啓動先後順序,而對於配置文件的管理也更加方便,接下來看下其常用語法。

語法

docker compose的配置是個yaml文件,在配置文件中容器將作為服務部署,docker compose幫我們統一管理這些服務,包括鏡像、啓動順序、網絡、數據卷、端口、重啓策略等等。配置中services、networks、volumes等這些都可以在最頂端定義表示需要創建的全局network、volume等等。

services

在Docker Compose中,services是定義容器的基本單位

語法:

services:
  <service_name>:
    <service_config>

其中,<service_name>是服務名稱,可以任意命名,但建議使用有意義的名稱。<service_config>是服務的配置信息,包含了運行服務所需的所有信息,如鏡像、容器名稱、端口映射、環境變量等。

例子:

version: '3'
services:
  web:
    image: nginx
    ports:
      - "8080:80"

image

services中的每個容器都是一個服務,其都會包含鏡像文件。鏡像可以指定第三方的,也可以使用本地Dockerfile進行構建

語法:

# 省略其他...
<service_config>
  # 使用第三方
  image: nginx:alpine

  # 本地構建
  build:
      context: .
      dockerfile: Dockerfile

你可以在容器中通過image指定第三方的鏡像文件,也可以使用build來進行本地鏡像的構建,build可以簡寫成build: your dir不需要指定上下文等等,其默認會使用當前目錄下的Dockerfile文件進行構建

ports、networks、volumes

除了容器中的鏡像外,其他如:端口、數據卷、網絡其實都是類似,並且和直接用docker run啓動容器時使用差不多

語法:

# 省略其他...
<service_config>
  image: nginx:alpine

  # 端口
  ports:
      - "<host_port>:<container_port>/<protocol>"
      - "1000"
      - "8080:80"
      - "443:443/tcp"

  # 數據卷
  volumes:
      - myvolume:/etc/data
      - /root/html:/etc/nginx/html

  # 網絡
  networks:
      - mynetwork

# 定義數據卷
volumes:
    myvolume:

# 定義網絡
networks:
    mynetwork:

上面展示了端口、數據卷、網絡的基本配置:

  • 端口:在容器中使用ports來定義端口的的映射,語法如上,當僅指定一個端口是<container_port>,這種就是告訴外面容器內使用了1000端口,你可以進行映射,實際上並沒有和宿主機進行映射而是一種定義,可dockerfile中的expose類似;使用<host_port>:<container_port>時前面表示宿主機端口,後者表示容器端口,二者進行映射;除此還支持協議,直接在最後加上/<protocol>即可
  • 數據卷:容器中使用volumes列表進行卷的映射,你可以直接使用宿主機的目錄進行映射,也可以使用docker創建的卷,並且你還可以使用沒有創建的數據卷,但同時你必須在頂級定義指定的數據卷,這樣docker會幫你自動創建數據卷
  • 網絡:使用網絡和數據卷類似,當使用不存在的自定義的網絡時,也需要在頂級進行定義

depends_on

使用depends_on字段來定義容器之間的依賴關係,以確保在啓動容器時,必須先啓動其所依賴的容器

語法:

depends_on:
  - <service_name>
  - <service_name2>
  ...

其中,<service_name>是所依賴的服務名稱,可以是單個服務或多個服務

例子:

version: '3'
services:
  db:
    image: mysql
  web:
    image: my-web-app
    depends_on:
      - db

在這個示例中,我們定義了兩個服務:一個名為db的服務,使用了mysql鏡像;一個名為web的服務,使用了自定義的web應用鏡像,並在depends_on字段中指定了db服務,表示web服務依賴於db服務。

在啓動這個Docker Compose文件時,Docker會先啓動db服務,然後再啓動web服務,以確保web服務可以連接到db服務並正常運行。

environment

可以使用environment字段來設置容器中的環境變量,其與docker run -e、Dockerfile中定義的ENV類似

語法:

environment:
  - <key>=<value>
  - <key2>=<value2>
  ...

其中,<key>是環境變量的名稱,<value>是環境變量的值。可以設置多個環境變量,每個環境變量之間用-分隔

例子:

version: '3'
services:
  web:
    image: my-web-app
    environment:
      MYSQL_HOST: db
      MYSQL_USER: user
      MYSQL_PASSWORD: password

在這個示例中,我們定義了一個名為web的服務,使用了自定義的web應用鏡像,並設置了三個環境變量:MYSQL_HOST、MYSQL_USER和MYSQL_PASSWORD。這些環境變量可以在容器內部使用,例如在web應用的配置文件中。

需要注意的是,如果在Docker Compose文件中定義了環境變量,而在Dockerfile中也定義了同名的環境變量,那麼Docker Compose文件中的環境變量會覆蓋Dockerfile中的環境變量。

除此之外還可以使用.env文件或命令行參數來設置環境變量。這樣可以避免將敏感信息硬編碼到Docker Compose文件中
:::warning 注意
Docker Compose文件中定義的環境變量會覆蓋.env文件中的同名環境變量
:::

.env配置文件示例:

MYSQL_HOST=db
MYSQL_USER=user
MYSQL_PASSWORD=password

compose文件配置:

version: '3'
services:
  web:
    image: my-web-app
    environment:
      MYSQL_HOST: ${MYSQL_HOST}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}

使用docker-compose命令的--env-file參數來指定環境變量文件。

restart

使用restart字段來定義容器的重啓策略,在容器異常退出或停止時,自動重新啓動容器

語法:

restart: <restart_policy>

其中,<restart_policy>是重啓策略,可以是以下幾種之一:

  • no:不重啓容器,默認值
  • always:總是重啓容器,除非手動停止容器
  • on-failure:在容器異常退出時重啓容器,可以使用-t選項指定重啓次數
  • unless-stopped:除非手動停止容器,否則總是重啓容器

例子:

version: '3'
services:
  web:
    image: my-web-app
    restart: always

在這個示例中,我們定義了一個名為web的服務,使用了自定義的web應用鏡像,並設置了重啓策略為always,表示總是重啓容器。需要注意的是,restart字段只會在容器異常退出或停止時才會生效,而不會影響容器的啓動順序或依賴關係。

更多

關於docker compose配置的講解就到這裏,其配置和docker run很相似,關於更多配置可以查看官方文檔

命令

有了配置文件後可以通過命令行對整個服務進行發佈、構建、刪除等等

docker compose [-f <arg>...] [--profile <name>...] [options] [COMMAND] [ARGS...]

build

docker compose build [OPTIONS]

用於構建Docker鏡像,可以通過一些參數來自定義構建過程:

  • --no-cache:禁止使用緩存進行構建。如果使用了緩存,Docker會在構建鏡像時儘可能地複用之前構建過的鏡像層,以提高構建速度。使用--no-cache選項可以強制Docker從頭開始構建鏡像
  • --pull:在構建鏡像之前,拉取最新的基礎鏡像。如果基礎鏡像版本已經過時,使用--pull選項可以確保構建的鏡像使用最新的基礎鏡像
  • --parallel:並行構建多個Docker鏡像。如果同時構建多個鏡像,可以使用--parallel選項加快構建速度

up

docker compose up [OPTIONS]

用於啓動Docker Compose定義的所有服務,可以通過一些參數來自定義啓動過程:

  • -d:在後台模式下啓動服務。如果不使用-d選項,則docker-compose up命令會在前台模式下啓動服務,並輸出日誌信息
  • --build:在啓動服務之前,自動構建鏡像。如果服務的鏡像已經存在,使用--build選項可以強制重新構建鏡像
  • --scale:擴展指定服務的容器數量。使用--scale選項可以根據實際需要動態地擴展服務的容器數量。

stop

docker compose stop [OPTIONS] [SERVICE...]

用於停止由Docker Compose定義的服務的容器,不會刪除容器、網絡和卷:

  • -t:停止服務的超時時間。使用-t選項可以指定停止服務的超時時間,單位為秒
  • SERVICE:指定要停止的服務,如果只需要停止一個或幾個服務的容器,可以在stop命令後面指定要停止的服務名

rm

docker compose rm [OPTIONS]

用於停止並刪除由Docker Compose定義的服務的容器、網絡和卷:

  • -f:強制停止並刪除服務的容器、網絡和卷。如果服務的容器正在運行或者網絡和卷正在被使用,使用-f選項可以強制停止並刪除它們
  • --stop:停止服務的容器,但不刪除它們。如果只想停止服務的容器而不刪除它們,可以使用--stop選項

kill

docker compose kill [OPTIONS] [SERVICE...]

用於強制停止由Docker Compose定義的服務的容器:

  • -s:指定信號量。使用-s選項可以指定要發送的信號量

更多

更多關於docker compose命令使用方法參考官方文檔

實戰

本次將部署兩個容器服務:前端和後端,其中前端使用nginx進行部署,後端使用nodejs作為api服務,將nginx端口映射到宿主機,然後通過宿主機IP:Port形式訪問前端頁面,頁面中請求後端服務,點擊這裏下載示例源碼。

  1. 創建前端頁面靜態文件index.html:頁面包括一個輸入框和一個按鈕,點擊發送請求到/api,這裏會請求nginx,nginx做反向代理到nodejs

    <input type="text">
    <button>發送</button>
    <script>
      const btn = document.querySelector("button")
      const input = document.querySelector("input")
      btn.addEventListener("click", () => {
          fetch(`/api?q=${input.value}`, {
          mode: "cors",
          method: "get"
        })
         .then(res => res.json())
         .then(res => console.log(res))
      })
    </script>
  2. 創建default.conf進行nginx的配置與轉發:當訪問/是返回前端頁面,頁面中的請求/api會被代理到compose-nodejs:10010,這裏的compose-nodejs是nodejs的服務名,只有當compose中的容器使用同一個網絡時才可以使用服務名的形式訪問

    upstream backend {
      server compose-nodejs:10010;
    }
    server {
      listen 80;
      server_name localhost;
      # 首頁靜態頁面
      location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
      }
    
      # 反向代理到 nodejs
      location /api {
          # 允許跨域
        add_header Access-Control-Allow-Origin $http_origin always;
        add_header Access-Control-Allow-Credentials true always;
        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
        add_header Access-Control-Allow-Headers 'content-type';
        if ($request_method = "OPTIONS") {
            return 204;
        }
    
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-Nginx-Proxy true;
        proxy_pass http://backend;
      }
    }
  3. 創建nodejs作為後端服務:nodejs使用express作為http服務,並監聽10010端口,當訪問時返回code和時間戳

    const express = require("express");
    const app = express();
    app.use((req, res) => {
      console.log(req.url);
      res.json({
        code: 200,
        date: +new Date(),
      });
    });
    app.listen(10010, () => console.log("server is runnning on port 10010"));
  4. 創建docker-compose.yml配置文件:裏面包含了nginx和nodejs容器,兩者都是用本地的Dockerfile進行構建鏡像,nginx映射宿主機10010端口到容器的80端口,並且兩者的啓動順序為compose-nodejscompose-nginx,使用相同的網絡compose

    version: "3"
    services:
      compose-nginx:
     build:
       context: .
       dockerfile: Dockerfile.nginx
     container_name: compose-nginx
     ports:
       - "10010:80"
     depends_on:
       - compose-nodejs
     networks:
       - compose
    
      compose-nodejs:
     build:
       context: .
       dockerfile: Dockerfile.nodejs
     container_name: compose-nodejs
     networks:
       - compose
    
    
    networks:
      compose:
  5. 創建鏡像構建文件:分別使用Dockerfile.nginxDockerfile.nodejs來構建nginx和nodejs鏡像,具體配置文件如下

    Dockerfile.nginx

    FROM nginx:alpine
    COPY index.html /usr/share/nginx/html
    COPY default.conf /etc/nginx/conf.d
    EXPOSE 80
    ENTRYPOINT [ "nginx", "-g", "daemon off;" ]

    Dockerfile.nodejs

    FROM node:alpine
    WORKDIR /app
    COPY package.json .
    RUN npm install
    COPY server.js .
    EXPOSE 10010
    ENTRYPOINT [ "npm", "run", "server.js" ]
  6. 啓動整體服務:

    docker compose up -d

參考文檔

  • Compose file build reference
  • The Compose file
  • Version and name top-level element
  • Services top-level element
  • Networks top-level element
  • Volumes top-level element
  • Configs top-level element
  • Secrets top-level element
  • Command line Guides
  • NodeJS Guides
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.