Docker極簡入門:使用Docker-Compose 執行網站瀏覽量統計Demo

AD_milk發表於2022-04-21

Docker-Compose 是一個可以對 Docker 容器叢集的快速編排的工具,能夠減輕您心智和手指的負擔。

簡單的來說 Docker-Compose 就是將你執行多個容器的命令編寫到了一起,類似於你會為一系列重複操作寫一個 doSomething.sh 檔案,只不過 Docker-Compose 提供了更簡便的語法。

當然如果想管理多主機多容器還是推薦使用 k8s。

我們的 demo 是一個基於 node.js 的網站服務,當使用者訪問當前伺服器的根目錄時,將 redis 中的瀏覽量計數增加1。

先不看具體的業務程式碼,這其實無關緊要。假設我們已經寫好了 node 服務,那麼我們下一步就是寫一個Dockerfile檔案去構建映象,然後執行 docker run 命令,這樣整個服務就啟動了。

FROM node:18-alpine

WORKDIR '/app'

COPY package.json .
RUN npm install
COPY . .
CMD ["npm","start"]

這個Dockerfile 做的事情就是

  • 在容器中建立一個 app 目錄,並切換到該目錄。
  • 將宿主機當前目錄下的 package.json 檔案拷貝到容器中的當前目錄(/app)下
  • 執行命令npm install
  • 將宿主機當前目錄下的所有檔案拷貝到容器中(因為主體程式index.js還沒有拷貝到容器中)
  • 執行命令npm start啟動服務

因為我們的 node 服務用到了 redis,所以我們還需要啟動一個 redis 容器。

但 docker 的機制使得這兩個容器是互相隔離的,所以想要通訊的話

  • 將 redis 埠與宿主機埠做對映,通過宿主機的埠訪問 redis
  • 建立 docker network,將兩個容器放在同一個 docker network下
  • 編寫 docker-compose.yml 檔案,讓Docker-Compose幫我們建立 docker network 搞定一切

docker-compose.yml

version: '3'
services:
  ## 容器名
  redis-server: 
   ## 指定映象
   image: 'redis:6.0.16-alpine'
   ## 容器重啟策略
   restart: 'always'
  ## 容器名
  node-app:
   ## 當前目錄執行 docker build
   build: .
   ## 埠對映
   ports: 
     - "8888:8081"

雖然我們在檔案中沒有寫任何有關 network 的程式碼,但 Docker-Compose會自動幫我們建立一個network

執行命令

sudo docker-compose up --build ## 會執行yaml檔案中的build命令

訪問 localhost:8888 你應該能看到類似這樣的介面

docker-compose 的命令跟 docker類似

docker-compose up -d ## 後臺執行
docker-compose down ## 停止

最後是檔案目錄結構和 index.js 以及 package.json的具體程式碼

.
├── docker-compose.yml
├── Dockerfile
├── index.js
├── package.json

package.json

{
    "dependencies": {
        "express": "^4.17.3",
        "redis": "^4.0.6"
    },
    "scripts": {
        "start": "node index.js"
    }
}

index.js

const express = require('express');

const redis = require('redis');

const app = express();

const client = redis.createClient({
  url : 'redis://redis-server:6379' // redis-server會被docker解析並轉發
});

const db = {
  async set(key,value){
    return fun(async()=>{
      return await client.set(key,value)
    },key,value)
  },
  async get(key){
    return fun(async()=>{
      return await client.get(key)
    },key)
  }
}

async function fun(callback,key,value){
  return new Promise(async (res,rej)=>{
    await client.connect();
    let ok = callback(key,value);
    await client.quit();
    res(ok);
  })
}

db.set("visits",0);

async function cntVisits(){
  let cnt = await db.get("visits");
  await db.set("visits",parseInt(cnt)+1);
  return parseInt(cnt)+1;
}

app.get('/', (req, res) => { 
    cntVisits().then( result => {
        res.send('Number of visits is ' + result); 
    });
});
// 8081是容器內部的埠,我們需要訪問的是8888,因為在docker-compose.yml檔案中已經做過埠對映了
app.listen(8081, () => { console.log('Listening on port 8081'); });

相關文章