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'); });