[手摸手系列] 使用 docker-compose 構建你的項目

前言

距離上一次在掘金寫文章,已通過去了半年多了(主要仍是本身水平差,不知道寫什麼好了)。node

不過新的一年,總要寫點東西總結總結一下。mysql

最近也一直在使用docker。因此就想者分享一下這方面的知識。不知道是否是最佳實踐,歡迎各位踩我nginx

1. Docker

docker的是什麼,在掘金平臺已經有不少篇文章有介紹了,我介紹的估計也沒他們好。因此就當你們有必定的Docker基礎了redis

因此這篇文章主要是實戰方面的內容,具體理論的話,能夠去搜搜其它文章瞭解學習一下。或者去官網sql

1.1 安裝

window 系統或者 macos 系統能夠直接去官網下載 Docker Desktop,連接:hub.docker.com/?overlay=on…docker

而後就是傻瓜式安裝了,這邊就不介紹了express

注意: window下須要企業版才能安裝,家庭版不能安裝(或者安裝比較麻煩)macos

1.2 docker-compose

在安裝完 Docker Desktop 後,會默認自動安裝好 docker-composenpm

能夠本身在命令行上試試,查看當前版本json

docker-compose -v
docker -v
複製代碼

2 準備項目

2.1 初始化一個node項目

  1. 初始化package.json
npm init -y
複製代碼
  1. 搭建一個http服務器 這邊使用的是express,用koa也行,看本身喜歡
npm install express
複製代碼
  1. 寫點代碼
let express = require('express')
let os = require('os')
let app = express()
// 獲取本機ip地址
function getLocalIpAddress () {
    let ip = ''
    let netInfo = os.networkInterfaces()
    let osType = os.type()
    if (osType === 'Windows_NT') { 
        for (const dev in netInfo) {
            // win7的網絡信息中顯示爲本地鏈接,win10顯示爲以太網
            if (dev === '本地鏈接' || dev === '以太網') {
                for (let j = 0; j < netInfo[dev].length; j++) {
                    if (netInfo[dev][j].family === 'IPv4') {
                        ip = netInfo[dev][j].address;
                        break;
                    }
                }
            }
        }
    } else if (osType === 'Linux') {
        ip = netInfo.eth0[0].address;
    }
    return ip
}
app.get('/getJson', (request, response) => {
    response.send({
        title: 'Hello Express、Hello Docker',
        ip: getLocalIpAddress(),
        env: process.env.NODE_ENV
    })
})
// 監聽3000端口
app.listen(3000, () => {
    console.log('server is started')
})
複製代碼
  1. 準備一個 Dockerfile 文件
  • Docker鏡像容器的關係就像實例的關係
  • 鏡像能夠經過Dockerfile文件來生成,容器經過鏡像來建立

Dockerfile用於生成鏡像

# 指定的一個基礎鏡像
FROM node:latest
# 工做目錄
WORKDIR /www/node-server/ # copy package.json 到工做目錄中
COPY package.json /www/node-server/package.json # 安裝依賴
RUN npm install # 拷貝當前目錄的文件到工做目錄中
# 若是有不須要忽略的文件,能夠寫在 .dockerignore 文件中,好比忽略 node_modules 文件夾
COPY . /www/node-server/ # 向外暴露3000端口
EXPOSE 3000
# 容器運行後執行的命令
CMD npm run start 複製代碼
  1. 構建鏡像
docker build .
複製代碼

  1. 構建成功後,建立容器
docker run --name node-server-1 -p 3000:3000 node-server
複製代碼
  1. 使用瀏覽器訪問 3000 端口看看是否啓動成功了

3.docker-compose構建

前面咱們要使用容器時,須要先定義 Dockerfile 文件,而後使用 docker builddocker run 等命令操做容器。

然而咱們的系統通常都包含上百的服務,每一個服務又有多個實例,若是全手動來啓動關閉的話,那工做量之大可想而知

那經過 docker-compose 能夠輕鬆、高效的管理容器,它是一個用於定義和運行多容器 Docker 的應用程序工具

3.1 配置docker-compose.yml 文件

  • 在項目目錄下建立一個 docker-compose.yml 文件
version: "3"
services: # 服務列表
 node: # node 服務
 build: . # Dockerfile 的目錄,用於構建鏡像
 container_name: node-server-1 # 容器名稱
 ports: # 暴露的端口
 - "3000:3000"
 restart: always # 自動重啓
 environment: # 設置環境變量
 - NODE_ENV=production
 command: npm run start # 覆蓋容器啓動後默認執行的命令
複製代碼
  • 構建鏡像
docker-compose build
複製代碼
  • 運行容器
docker-compose up -d
複製代碼

不出意外的話,經過瀏覽器訪問3000端口也是能正常訪問

3.2 編排多個服務

好比咱們如今須要構建一個 nginx服務來將請求代理到咱們的 node-server,那咱們須要構建兩個服務

那麼問題來了

  • nginx容器如何使用個人本身的nginx.conf配置文件

    • 能夠經過 volumes 文件映射
  • nginx容器和 node-server 容器如何進行通訊

    1. 可使用 docker-inspect 命令來查看 node-server 容器的IP地址,而後修改nginx.conf的配置、
    2. 使用networkslinks

    docker容器每次從新構建運行時,IP 地址不必定是同樣的,因此每次都要修改nginx.conf的配置,因此方案1的效率顯然是低下的。

  • 新增一個 nginx.conf 配置文件

worker_processes 1;

events {
    worker_connections 1024;
}
http {
    upstream node-server {  
        server node:3000;
    } 
    server {
        listen 80;
 
        server_name localhost;
 
        location / {
            proxy_pass http://node-server/;
        }
    }
}
複製代碼
  • 從新修改一下 docker-compose.yml 文件
# docker-compose.yml
version: "3"
services: # 服務
 node: # node 服務
 build: . # Dockerfile 的目錄,用於構建鏡像
 container_name: node-server-1 # 容器名稱
 ports: # 暴露的端口
 - "3000:3000"
 restart: always # 自動重啓
 environment: 
 - NODE_ENV=production
 networks: # 加入網絡
 - "my-network"
 command: npm run start # 覆蓋容器啓動後默認執行的命令
 nginx:
 image: nginx:latest 指定 nginx 鏡像
 ports: # 將本機的 8080 端口映射到容器的80端口
 - "8080:80"            
 container_name: nginx-node
 restart: always
 volumes: # 映射本機 F:/nginx.conf 文件到 容器的 /etc/nginx/nginx.conf:ro 文件
 - "F:/nginx.conf:/etc/nginx/nginx.conf:ro"
 networks: 
 - "my-network"
 links: # 設置 node 服務別名,實際上是設置/etc/hosts的域名解析
 - "node"
 depends_on: # 指定依賴於哪一個服務
 - node
networks: # 網絡
 my-network: # 網絡名稱
 driver: bridge
複製代碼
  • 從新構建
# 刪除上次構建的容器
docker-compose down
# 從新構建鏡像 --force-rm 刪除構建過程當中的臨時容器。
docker-compose build --force-rm
# 運行容器
docker-compose up -d
複製代碼

不出意外的話,經過瀏覽器訪問本地的8080端口,是能夠訪問到 node-server

按着上面的套路,能夠繼續擴展 redismysql服務等,也是經過加入 networklinks 來進行相互通訊

這部分就不進行介紹了

4. 水平擴展 node 服務

當用戶量比較小的狀況下,咱們一個 node 服務就夠用了,當用戶量大的時候,就一個 node 服務的話,就顯得力不從心了。

通常狀況下都是升級機器,加服務,經過 nginx進行負載均衡

那咱們如何經過 docker-compose 快速的水平擴展服務呢?

4.1 scale

docker-compose 給咱們提供了一個 scale 命令,用於在本機下快速構建多個服務

# 刪除上次構建的容器
docker-compose down
# 從新構建鏡像 --force-rm 刪除構建過程當中的臨時容器。
docker-compose build --force-rm
# 運行容器 增長 --scale node=5
docker-compose up -d --scale node=5 
複製代碼

經過--scale node=5咱們構建5個node服務

不過不出意外的話,是會構建失敗的,報端口占用錯誤

由於咱們的每一個node服務都佔用了 3000 本機的端口。

因此咱們須要修改一下 docker-compose.yml 文件,只暴露容器的3000端口,不暴露本機的端口

# docker-compose.yml
version: "3"
services: # 服務
    node: # node 服務
        build: . # Dockerfile 的目錄,用於構建鏡像
        # container_name: node-server-1 # 容器名稱
        # ports: # 暴露的端口
        # - "3000:3000"
        expose:
            - "3000"
        restart: always # 自動重啓
        environment: 
            - NODE_ENV=production
        networks: # 加入網絡
            - "my-network"
        command: npm run start # 覆蓋容器啓動後默認執行的命令
    nginx:
        image: nginx:latest 指定 nginx 鏡像
        ports: # 將本機的 8080 端口映射到容器的80端口
            - "8080:80"            
        container_name: nginx-node
        restart: always
        volumes: # 映射本機 F:/nginx.conf 文件到 容器的 /etc/nginx/nginx.conf:ro 文件
            - "F:/nginx.conf:/etc/nginx/nginx.conf:ro"
        networks: 
            - "my-network"
        links: # 設置 node 服務別名,實際上是設置/etc/hosts的域名解析
            - "node"
        depends_on: # 指定依賴於哪一個服務
            - node
networks: # 網絡
    my-network: # 網絡名稱
        driver: bridge
複製代碼
  • 從新運行
# 運行容器 增長 --scale node=5
docker-compose up -d --scale node=5 
複製代碼

不出意外的話,此次能夠構建成功

經過 docker ps -a 能夠查看當前運行的容器

docker ps -a
複製代碼

不出意外的話,經過nginx訪問,負載均衡沒有生效,每次訪問獲得的ip地址一直是同一個

4.2 修改nginx配置文件

咱們經過 docker inspect nginx-node 命令,在查看一下 nginx 容器的信息

docker inspect nginx-node
複製代碼

能夠看到 "node-server_node_3:node",咱們nginx配置了server node:3000;,因此每次請求,nginx都將請求代理到node-server_node_3這個node服務上了,

upstream node-server {  
    server node:3000;
} 
複製代碼

因此咱們修改一下 nginx.conf 配置,這樣就能將請求代理到不一樣的機器上了

upstream node-server {  
    upstream node-server {  
        server node_1:3000 weight=3; # 加權重
        server node_2:3000;
        server node_3:3000;
        server node_4:3000;
        server node_5:3000;
    }
} 
複製代碼

5. 總結

咱們目前的擴展是單機環境下的scale,不管將service擴展到多少,只能限制在單機環境下。可是一臺服務器的資源是有限的,那麼如何擴展多臺服務器?那麼就是須要使用swarm技術了。這個接下來有機會在分享吧

因爲技術水平有限,有寫的很差的地方歡迎指出,輕噴!

歡迎關注

歡迎關注公衆號「碼上開發」,天天分享最新技術資訊

image
相關文章
相關標籤/搜索