[譯] 寫給前端工程師的 Docker 入門

savokiss發表於2019-07-28

為什麼我們要用 docker ?

過去的我們,當業務發展需要部署新的應用時,DevOps 小夥伴通常會去買一臺伺服器,但是卻不知道這個新應用具體需要多高的配置,往往都會造成資源浪費。

當虛擬機器出現後,它可以讓我們在一臺伺服器上執行多個應用,但是卻有一個缺陷。每個 VM 需要執行一整個的作業系統。每個 OS 又需要 CPU、RAM 等等,需要打補丁、安裝證書,這些反過來又增加了成本和彈性。

Google 在很久之前就開始使用容器模型來解決 VM 模式的弊端。簡單來說容器模型允許我們在同一臺主機上執行多個容器,而且共用主機的 CPU、RAM 等資源。

那麼它對開發者來說意味著是麼呢?

它可以保證對所有的開發者和伺服器來說,我們的工作環境都是一致的。比如: 生產環境、模擬環境、測試環境。

任何人都可以分分鐘配置好專案,無需亂搞配置、安裝庫和設定依賴。

簡單來說,docker 是一個平臺,它允許我們使用容器來開發、部署、執行應用程式。

讓我們退一步來看,容器系統在物理上是什麼樣子的,以及與 VM 有什麼區別。

1-vm-and-docker.png

可以看出來,宿主機的資源在容器化的使用後是共享的,但是在 VM 中卻被分割開了。

接下來,我們來深入一些。

如何使用 docker ?

為此我們需要先熟悉一些術語。

2-images-and-container.png

Docker image: 它是一個可執行檔案,包含了執行一個應用程式的作業系統配置和所有的庫。它有多個層疊在一起,並表示為單個物件。docker image 是通過 docker file 來建立的,我們稍後再講。

Docker Container: 它是 docker image 的一個執行例項。同一個 docker image 可以有多個執行的 container。

容器化 Node.js 應用

我們來嘗試容器化一個簡單的 node.js 應用,然後建立一個 image:

你的 Node.js 應用

先建立一個 my-node-app 資料夾,

mkdir my-node-app
cd my-node-app

然後建立一個 index.js 來啟動一個 node server:

// 我們用 require 引入 express

var express = require('express')

var app = express()

// 對根 URL 做一個響應
app.get('/', function (req, res) {  
 res.send('Hello World!')  
})

// 讓伺服器監聽 8081 埠
app.listen(8081, function () {  
  console.log('app listening on port 8081!')  
})

然後我們建立一個 package.json 檔案,可以通過 npm init -y 來快速生成:

 {

    "name": "helloworld",  
    "version": "1.0.0",  
    "description": "Dockerized node.js app",  
    "main": "index.js",  
    "author": "",  
    "license": "ISC",  
    "dependencies": {  
      "express": "^4.16.4"  
    }
 }

到這一步我們甚至不需要 express 或者 npm 安裝在自己的機器,因為 dockerfile 可以為我們配置和安裝這些依賴。

DockerFile

讓我們建立一個 dockerfile,然後儲存到 my-node-app 資料夾。這個檔案沒有副檔名,它的名字就叫作 Dockerfile,這是裡面的內容:

# Dockerfile
FROM node:8
WORKDIR /app
COPY package.json /app
RUN npm install
COPY . /app
EXPOSE 8081
CMD node index.js

下面解釋一下里面的命令:

FROM node:8 -- 從 docker hub 拉取 node.js docker 映象,可以在這裡找到 node 的映象:https://hub.docker.com/_/node/

WORKDIR /app -- 設定映象中的工作目錄,可以與下面的命令一起使用: COPYRUNCMD

COPY package.json /app -- 將 package.json 從宿主機的 my-node-app 目錄複製到了映象中的 /app 目錄

RUN npm install -- 在映象中執行此命令來安裝 node 包

COPY . /app -- 複製 my-node-app 目錄中的所有檔案到映象中的 /app 目錄

EXPOSE 8081 -- 這條命令告訴 container 要暴露一個埠號,這個埠號正是我們在 index.js 中寫的那個。預設情況下,容器會忽略對它所有的請求。

構建 Docker 映象

注意看啦~ 開啟控制檯,到 my-node-app 目錄下,執行以下命令:

 # Build a image docker build -t <image-name> <relative-path-to-your-dockerfile>

 docker build -t hello-world .

這條命令在我們宿主機建立了一個 hello-world 映象

-t 用來為我們的映象指定一個名字,這裡就是 hello-world

. 是用來指明 docker file 的路徑,由於我們已經在 my-node-app 中,所以路徑用 . 就可以了

你可以在控制檯看到類似於以下的輸出:

Sending build context to Docker daemon  4.096kB  
Step 1/7 : FROM node:8  
 ---> 4f01e5319662  
Step 2/7 : WORKDIR /app  
 ---> Using cache  
 ---> 5c173b2c7b76  
Step 3/7 : COPY package.json /app  
 ---> Using cache  
 ---> ceb27a57f18e  
Step 4/7 : RUN npm install  
 ---> Using cache  
 ---> c1baaf16812a  
Step 5/7 : COPY . /app  
 ---> 4a770927e8e8  
Step 6/7 : EXPOSE 8081  
 ---> Running in 2b3f11daff5e  
Removing intermediate container 2b3f11daff5e  
 ---> 81a7ce14340a  
Step 7/7 : CMD node index.js  
 ---> Running in 3791dd7f5149  
Removing intermediate container 3791dd7f5149  
 ---> c80301fa07b2  
Successfully built c80301fa07b2  
Successfully tagged hello-world:latest

可以看到,它根據 docker file 中的命令依次執行,然後輸出了一個 docker 映象。當你第一次執行的時候可能會需要一些時間,下次就可以使用快取來加快速度了。現在我們來看下剛才 build 的映象:

 # Get a list of images on your host 
 docker images

這個命令會顯示在你電腦上存在的 docker 映象。其中會有一條:

REPOSITORY    TAG      IMAGE ID      CREATED         SIZE  
hello-world   latest   c80301fa07b2  22 minutes ago  896MB

執行 Docker 容器

既然我們已經建立了映象,下面我們就從這個映象執行一個 docker 容器:

# Default command for this is docker container run <image-name>  
 docker container run -p 4000:8081 hello-world

這條命令用來建立和執行一個 docker 容器

-p 4000:8081 -- 是一個釋出(publish)標識,它將本機的 4000 埠對映到了容器中的 8081 埠。現在所有對本機 4000 埠的訪問,都會被容器中的 8081 埠監聽。

hello-world -- 這個名字就是剛才用 docker build 命令時指定的映象名稱。

你將會得到以下輸出:

app listening on port 8081!

如果你需要進入容器並且掛載一個 bash 終端,可以執行:

# Enter the container
docker exec -ti <container id> /bin/bash

為了檢查我們的容器是否執行,開啟另一個命令列,然後輸入:

docker ps

可以看到以下輸出:


 CONTAINER ID    IMAGE        COMMAND                  CREATED    
 `<container id>`  hello-world  "/bin/sh -c 'node in…"   11 seconds ago

 STATUS              PORTS                    NAMES  
 Up 11 seconds       0.0.0.0:4000->8081/tcp   some-random-name

這裡可以看我們從 hello-world 映象建立的容器,以及它的 <container id> ,它正在執行,並且監聽了 8081 埠號。

現在我們這個簡單的 Node.js 應用就已經完全容器化了。你可以在瀏覽器訪問 http://localhost:4000 ,應該可以看到以下畫面:

3-localhost.png

看,是不是很簡單哈哈~

原文連結


歡迎關注我的公眾號:碼力全開(codingonfire)
codingonfire.jpg

相關文章