歡迎光臨
每天分享高質量文章

9102 年了,學點 Docker 知識

最近工作需要,開發時需要用到 Docker。這篇文章從零開始演示幾個 Demo,如果你之前沒接觸過 Docker,可以一步步跟著操作,加深對 Docker 的理解。
Docker 能解決什麼問題

 

無論你所處的公司大或小,多多少少都遇到開發環境和生產環境不一致的問題。有些開發者用 Windows,有些開發者用 Mac,而生產環境可能用的是 Linux,同時跑著多個應用,每個應用依賴的 Node 版本版本不一致,不同服務可能還占用相同的端口。於是我們常常聽到這樣的疑問:“本地明明是好的啊,為什麼到線上就不行了?”
(我自己的親身經歷:很早以前開發前端專案,我需要在本地搭建 LEMP 環境,照著教程搗鼓好幾天,一行前端代碼都沒有寫。後來還因為一些“莫名其妙”的問題,反反覆復重裝了好幾次。)
而使用了 Docker 之後呢,我們能通過配置檔案一條命令快速構建環境,並且可以做到和其他服務隔離,互不影響,通過例子來講解。
演示環境

 

這篇文章執行的環境是 macOS 10.14.1,Docker version 18.09.0。
概念:鏡像 vs 容器

 

鏡像是以一些列歷史操作疊加而成的,對鏡像的每一次操作都會產生新的只讀層,比方說你往容器寫入內容,提交,再把它移除,則會產生兩個歷史只讀層,有點像 git commits,而容器可以理解問為鏡像歷史層 + 可寫層的可運行系統,在可寫層做任何操作都沒問題,不提交的話,容器被刪除後相應的改動也會丟失,有點像 Git 暫存區。(個人理解,不一定對) 
安裝 Docker

 

Mac 安裝 Docker:
  1. brew cask install docker
其他環境安裝 Docker 查看這裡[1]。
安裝完成之後,執行 hello-world 試一下。
  1. $ docker run hello-world
  1. Unable to find image 'hello-world:latest' locally
  2. latest: Pulling from library/hello-world
  3. 1b930d010525: Pull complete
  4. Digest: sha256:2557e3c07ed1e38f26e389462d03ed943586f744621577a99efb77324b0fe535
  5. Status: Downloaded newer image for hello-world:latest
  6.  
  7. Hello from Docker!
  8. This message shows that your installation appears to be working correctly.
這條命令會連接本地 Docker 服務,Docker 服務檢測到本地沒有 hello-world 鏡像,於是去 Docker 鏡像市場下載這個鏡像,然後創建新的容器,運行特定的命令,輸出 Hello from Docker!
這篇文章不講解 Docker 有哪些基礎命令,直接從案例入手。
啟動 Nginx 服務

 

  1. docker run -d -p 80:80 --restart=always  nginx:latest
引數說明:
  • run 啟動某個鏡像

  • -d 讓容器在後臺運行

  • -p 指定端口映射,宿主機的80端口映射到容器的80端口

  • –restart 重啟樣式,設置 always,每次啟動 Docker 都會啟動 Nginx 容器。

由於我本地沒有 nginx:latest 的鏡像,同樣會先去鏡像市場下載。啟動完成打開 http://localhost:80 就能立馬看到 Nginx 的歡迎頁面。 
如果想修改歡迎頁面,可以進入到容器內修改頁面。
  1. docker exec -it 4591552a4185 bash
引數說明:
  • exec 對容器執行某些操作

  • -it 讓容器可以接受標準輸入並分配一個偽tty

  • 4591552a4185 是剛剛啟動的 Nginx 容器唯一標記

  • bash 指定交互的程式為 bash

Nginx 預設檔案路徑是 /usr/share/nginx/html/index.html ,直接用 echo 寫入內容即可。
  1. echo '

    Hello Docker

    > /usr/share/nginx/html/index.html

ctrl + D 退出容器,重新訪問 localhost:80 即可看到 Hello Docker。 
每次修改內容都需要手動進入容器,太過繁瑣,並且上面提到了,對容器的直接修改不會持久儲存,如果容器被刪,資料也會跟著丟失。
(由於之前的 demo 已經占用了 80 端口,咱們先 kill 掉它。)
  1. docker kill 4591552a4185
Docker 提供資料掛載的功能,即可以指定容器內的某些路徑映射到宿主機器上,修改命令,添加 -v 引數,啟動新的容器。
  1. docker run -d -p 80:80  -v ~/docker-demo/nginx-htmls:/usr/share/nginx/html/ --restart=always  nginx:latest
啟動成功之後,Docker 會幫你生成目錄 ~/docker-demo/nginx-htmls,現在裡面什麼都沒有,添加個 index.html。 
再次打開 http://localhost:80,同樣能看到 Hello Docker。
 
接著我們來用 Node + Redis + Docker 做一個 PV 展示的 demo。
運行命令:
  1. docker run -d -p 6379:6379 -v ~/docker-demo/redis:/data redis:latest
啟動一個 Redis 容器,並將資料持久化到 ~/docker-demo/redis 目錄。(考慮性能,Redis 並不會實時寫入資料到磁盤)
用 koa 啟動一個 node server,並連接 Redis , 每次訪問 / 都給計數器加一。
  1. const Redis = require('ioredis');
  2. const Koa = require('koa');
  3. const Router = require('koa-router');
  4.  
  5. const router = new Router();
  6. const app = new Koa();
  7.  
  8. const redis = new Redis(`redis://127.0.0.1:6379/0`);
  9.  
  10. router.get('/', async (ctx, next) => {
  11.  await next();
  12.  await redis.incr('pv');
  13.  const current = await redis.get('pv');
  14.  ctx.body = `current pv: ${current}`;
  15. });
  16.  
  17. app
  18.  .use(router.routes())
  19.  .use(router.allowedMethods());
  20.  
  21. app.listen(3000);
訪問 http://localhost:3000,就能看到輸出結果。 
推薦使用 medis 可視化查看 Redis 資料。 
OK,開發環境完成功能開發,交付運維上線。我們假設生成環境會啟動四個 Node 服務,一個 Redis 服務,和一個 Nginx 做負載。
這時候需要把我們的 Node 服務也構建成鏡像,新增 Dockerfile 檔案。
  1. # 基於最新的 node 鏡像
  2. FROM node:latest
  3. # 複製當前目錄下所有檔案到標的鏡像 /app/ 目錄下
  4. COPY . /app/
  5. # 修改工作目錄
  6. WORKDIR /app/
  7. # yarn 一下,安裝依賴
  8. RUN ["yarn"]
  9. # 啟動 node server
  10. ENTRYPOINT ["node", "index.js"]
更多 Dockerfile 指令看這裡[2]。
可以在本地構建一下,運行命令 docker build . –tag=pv,然後通過 docker images 就能看到剛剛構建的新鏡像。
繼續往下走,編排一組容器,docker 官方提供了 docker-compose 工具。在專案目錄下新增 docker-compose.yml 檔案。
  1. # 使用 docker-compose 2.2 版本
  2. version: "2.2"
  3. # 定義 services
  4. services:
  5.  redis:
  6.    image: redis:latest
  7.    volumes:
  8.      - "~/docker-demo/pv/data/:/data/"
  9.  
  10.  web:
  11.    # 放大4倍,也就會有四個 node server
  12.    scale: 4
  13.    build: .
  14.    # 新增環境變數
  15.    environment:
  16.      - REDIS_HOST=redis://redis:6379/0
  17.    # 依賴關係
  18.    depends_on:
  19.      - redis
  20.  
  21.  nginx:
  22.    image: nginx:latest
  23.    depends_on:
  24.      - web
  25.      - redis
  26.    ports:
  27.      - 80:80
  28.    volumes:
  29.      - "./default.conf:/etc/nginx/conf.d/default.conf"
更多 docker-compsoe 指令看這裡[3]。
service web 新增環境變數 REDIS_HOST=redis://redis:6379/0 是給 ioredis 鏈接用的,對應的要修改 js 檔案。
  1. const redis = new Redis(process.env.REDIS_HOST);
redis://redis:6379/0 第一個 Redis 是協議,第二個 Redis 是 service host。service 之間可以通過 host 互相通信。
複製 Nginx 容器下的 default.conf 檔案出來修改:
  1. upstream web {
  2.  server pv_web_1:3000;
  3.  server pv_web_2:3000;
  4.  server pv_web_3:3000;
  5.  server pv_web_4:3000;
  6. }
  7.  
  8. server {
  9.    #...
  10.  
  11.    location / {
  12.      proxy_pass http://web;
  13.    }
  14.  
  15.    #...
  16. }
新增上游服務 Web,這裡的 PV 是我的專案檔案名,Web 是 docker-compose 檔案中定義的 service name,1 – 4 則是 scale 出來 Docker 自動給定的序號。啟動起來之後,Nginx 訪問 http://pvweb1:3000 的請求就會到達第一個 Web 容器。
萬事具備,let’s compose up!
好了,現在訪問 http://localhost:80。 
到目前為止,我們已經把應用部署完成,每次訪問 PV 數量自動加一,並且經過 Nginx 負載均衡,會隨機打到不同的容器上面。
總結

 

這篇文章演示了和前端相關的一些 Docker 操作,從中我們可以看到其對於軟體的開發,測試,部署都帶來了極大的便利。文中的內容僅僅是冰山一角,示例也只能作為學習使用,請不要直接用在生產環境。同時部分內容是個人理解,沒有權威性,深入學習 Docker ,你應該去看詳細的文件。
相關鏈接:

  1. https://yeasy.gitbooks.io/dockerpractice/install/

  2. https://yeasy.gitbooks.io/dockerpractice/image/dockerfile/

  3. https://yeasy.gitbooks.io/docker_practice/compose/

原文鏈接:https://juejin.im/post/5c2c69cee51d450d9707236e

 

Kubernetes實戰培訓

 

Kubernetes實戰培訓將於2019年3月8日在深圳開課,3天時間帶你系統掌握Kubernetes,學習效果不好可以繼續學習本次培訓包括:雲原生介紹、微服務;Docker基礎、Docker工作原理、鏡像、網絡、儲存、資料捲、安全;Kubernetes架構、核心組件、常用物件、網絡、儲存、認證、服務發現、調度和服務質量保證、日誌、監控、告警、Helm、實踐案例等。
    閱讀原文

    赞(0)

    分享創造快樂