《前端運維》三、Docker--2其他

Zaking發表於2022-03-26

一、製作DockerFile

   docker的映象類似於用一層一層的檔案組成。inspect命令可以檢視映象或容器的的資訊,其中Layers就是映象的層檔案,只讀不能修改,基於映象建立的容器會共享這些層。下面我們先來學習一下dockerFile中的一些命令:

  1. form,構建的新映象是基於哪個映象
    • form centos:6
  2. maintainer,映象維護者姓名或郵箱地址。
    • maintainer zaking。
  3. run,構建映象時執行的shell命令。
    • RUN yum install httpd
  4. cmd,設定容器啟動後預設執行的命令及其引數,但cmd能夠被docker run後面的命令及引數替換。cmd給出的是一個容器的預設的可執行體。也就是容器啟動以後,預設的執行的命令。重點就是這個"預設"。意味著,如果docker run沒有指定任何的執行命令或者dockerfile裡面也沒有entrypoint,那麼,就會使用cmd指定的預設的執行命令執行。同時也從側面說明了entrypoint的含義,它才是真正的容器啟動以後要執行命令。
    • CMD /usr/sbin/sshd -D
  5. expose,宣告容器執行的埠。
    • EXPOSE 80 443
  6. env,設定容器內的環境變數。
    • ENV MYSQL_ROOT_PASSWORD 123456
  7. add,拷貝檔案或目錄到映象中,如果是URL或者壓縮包會自動下載和解壓。
  8. copy,拷貝檔案或目錄到映象。
    • COPY ./start.sh /start.sh
  9. entrypoint,配置容器啟動時執行的命令。
    • ENTRYPOINT /bin/bash -c '/start.sh'
  10. volume,指定容器掛載點到宿主自動生成的目錄或其它容器。
    • VOLUME ["/var/lib/mysql"]
  11. user,為 RUN CMD和ENTRYPOINT執行命令指定執行使用者。
    • USER zaking
  12. workdir,為RUN CMD ENTRYPOINT COPY ADD 設定工作目錄。
    • WORKDIR /data
  13. healthcheck,健康檢查。
    • HEALTHCHECK --interval=5m --timeout=3s --retries=3 CMS curl -f htp://localhost
  14. arg,在構建映象時指定一些引數。
    • ARG user

  ok,我們對基本的命令有了些許的瞭解,哦對,強調一下,以上寫在dockerfile中的欄位要大寫,那麼我們下面來實踐一下,看如何自定義一個映象:

  首先啊,我們來安裝一下node(因為我們實踐來建立一個node映象):

yum install -y epel-release
yum install -y nodejs

  先安裝附加軟體包,然後就可以通過yum命令安裝nodejs了。node -v檢視下,沒問題的。安裝完node後,我們再來安裝一個express的專案生成器,快速生成一個node專案:

npm install express-generator -g

  準備工作做好了,我們先來建立資料夾,檔案的結構是這樣的:

cd /
mkdir docker-hub
cd docker-hub
mkdir zakingnode
cd zakingnode 
touch Dockerfile
express nodedemo
ls

  最後我們在docker-hub目錄下,建立了一個nodedemo專案,和一個Dockerfile檔案。 然後我們來編輯一下Dockerfile,內容如下:

# FROM表示該映象繼承的映象 :表示標籤
FROM node
LABEL name="zaking" version='1.0'
# COPY是將當前目錄下的app目錄下面的檔案都拷貝到image裡的/app目錄中
COPY ./nodedemo /nodedemo 
# WORKDIR 指定工作路徑,類似於執行 cd 命令
WORKDIR /nodedemo
USER root
# RUN npm install 在/app目錄下安裝依賴,安裝後的依賴也會打包到image目錄中
RUN npm install
# EXPOSE 暴露3000埠,允許外部連線這個埠
EXPOSE 3000
ENV MYSQL_ROOT_PASSWORD 123456
CMD npm start

  其中LABEL是MAINTAINER的替代,新的Docker版本已經不支援MAINTAINER欄位了。然後我們建立一個.dockerignore,類似於gitignore,就是docker不要打包到image中的檔案。裡面寫上:

.git
node_modules

  很常見的配置。然後我們通過build命令,來生成這個映象:

docker build -t nodedemo:1.0.0 .

  build後面的引數,-t用來指定image映象的名稱,後面還可以加冒號指定標籤,如果不指定預設就是latest。-f指dockerfile檔案的位置,可以直接設定'.',意味著在當前目錄自己找。然後等會就成功了。我們通過docker image ls看一下:

   這樣就ok了。下面我們看如何這個自定義映象來執行容器。

docker run -p 3333:3000 nodedemo:1.0.0

   然後開啟另一個命令列,訪問一下剛才的啟動的容器。其實就跟我們之前的例子沒什麼區別。當然,我們也可以進行手動啟動。方式是刪除之前Dockerfile中的CMD部分的命令。直接啟動容器進入偽終端,在偽終端中手動npm start啟動node服務。之前有過類似的例子,這裡就不多說了。

  剩下的呢就是釋出我們們自定義的容器了,這個之前也簡單說過,沒啥區別,就是註冊個賬號,push到遠端,沒了。

二、資料盤

  當你刪除容器的時候,容器層裡建立的檔案也會被刪除,如果有些資料你想要永久儲存,比如Web伺服器的日誌,資料庫中的資料等,那麼就可以為容器建立一個資料盤。volume,就是Docker管理宿主機檔案系統的一部分(/var/lib/docker/volumes)。如果沒有指定卷,則會自動建立。

  下面,我們就直接實踐下有關的命令:

1、建立資料卷

   這樣,我們就建立了一個名為nginx-vol的資料卷。通過inspect命令,可以檢視詳細的資料卷資訊:

   然後,可以通過rm命令刪除資料卷:

docker volume rm nginx-vol

2、資料卷掛載

  我們先來執行下下面的命令:

docker run -d --name=nginx1 --mount src=nginx-vol,dst=/usr/share/nginx/html -p 3000:80 nginx

  上面程式碼的意思就是,根據nginx映象啟動一個容器,名字叫做nginx1,如果不指定會有個自動生成的名字,指定掛載的資料卷的原始檔名字是nginx-vol。回車後,還記inspect那個命令不,可以檢視下Mountpoint路徑下的檔案:

   就是nginx,靜態目錄下,也就是我們剛才執行的命令中的引數設定的。然後我們在這個路徑下,建立個html檔案以供我們訪問,隨便啥html檔案都行,寫點內容就行。

   然後開啟另一個命令視窗,來訪問下:

   就成功了。額外要說的就是,該命令的還有另外一種簡寫形式,這裡簡單寫下,都能看懂,不多說了:

docker run -d --name=nginx1 -v nginx-vol:/usr/share/nginx/html -p 3000:80 nginx

  下面,我們把正在執行中的容器都停止並刪除,怎麼刪之前也實踐很多次了。然後我們在/var/lib/docker/volumes/nginx-vol/_data,這個目錄下檢視下,發現之前建立的檔案並沒有消失。

3、指定資料盤

  我們先建立個mnt的目錄,並在其中建立個hello.html檔案:

   然後我們執行這樣的命令:

docker run -v ~/mnt:/mnt -it --name logs centos bash

  大部分的意思大家都知道,就是多了個-v引數,-v實際上就是volume,/mnt:/mnt的意思就是宿主機的/mnt目錄對映到容器內的/mnt目錄。

   我們在容器內建立一個檔案:

   下面是宿主機的:

   大家看到了是同步的對吧。在宿主機建立,也同樣可以在容器內生成,這個大家可以自己去試一下。

4、指定資料盤容器

   我們先來執行下這個命令:

docker create -v ~/mnt:/mnt --name logger centos 

  這樣就直接建立了一個具有指定資料卷容器的容器。稍後,我們就可以執行這個容器:

docker run --volumes-from logger --name loga -it centos bash

  我們就進入到容器的命令列內了,然後,我們就可以重複之前的試驗了,這裡不多說了哈,都一樣。

 三、Docker網路

   安裝docker時,會自動建立三個網路:bridge、host、none。其中,none意味著關閉了容器的網路功能,對外界完全隔離。host意味著容器不會虛擬自己的網路卡,分配ip等,而是使用宿主機的埠和ip,bridge模式會給每一個容器分配一個ip。

docker inspect bridge

  上面的命令可以檢視docker容器中網路連線模式是bridge的有哪些。

  下面,我們先在後臺執行兩個容器:

docker run -d --name=nginx1 nginx
docker run -d --name=nginx2 nginx

  然後進入nginx2的偽終端:

docker exec -it nginx2 bash

  在nginx2的偽終端中,更新下apt,並安裝一些依賴:

apt update
apt install -y inetutils-ping  #ping
apt install -y dnsutils        #nslookup
apt install -y net-tools       #ifconfig
apt install -y iproute2        #ip
apt install -y curl            #curl

  然後,看下/etc/hosts檔案:

cat /etc/hosts

  然後就你在nginx1中也要做相同的操作,然後再nginx1中就可ping nginx2的ip了:

ping [nginx2‘s ip]

  然後呢,我們可以通過--net選項,來指定容器的網路連線模式:

docker run -d --name=nginx_none --net=none nginx

  然後就是,你還得安裝之前的那些依賴,當然,你想要通過inspect來檢視資訊也可以,但是不夠具體吧,我沒還是進入到這個nginx_none容器的偽終端,安裝一些依賴,這就不多說了吧。

   哎?臥槽?不對啊,安裝報錯了,嗯。。。報錯就對了,因為你壓根沒網路啊。host模式也不麻煩,這裡就不演示了,設定之後,你測試下跟宿主機的ip是否一直就ok咯。

  另外,host模式,啟動的時候要注意埠占用的問題,也就是宿主機中啟動了一個nginx,佔用了80埠,那麼,此時你是無法通過host模式啟動容器的。那麼,我們就需要學習一下埠對映:

# 讓宿主機的8080埠對映到docker容器的80埠
docker run -d --name port_nginx -p 8080:80  nginx
# 檢視主機繫結的埠
docker container port port_nginx

  也可以通過下面的命令,隨機建立容器指向宿主機的埠號:

docker run -d --name random_nginx --publish 80 nginx
docker port random_nginx

docker run -d --name randomall_nginx --publish-all nginx
docker run -d --name randomall_nginx --P nginx

  在docker中,我們也可以嘗試自定義網路,網路可以建立多個,且每個網路的ip範圍均不相同,docker的自定義網路中有一個DNS服務,可以通過容器名訪問到主機。

docker network create --driver bridge myweb

  然後呢,我們就可以像使用橋接網路那樣,使用我們的自定義網路:

docker run -d --name mynginx1  --net myweb nginx
docker run -d --name mynginx2  --net myweb nginx
docker exec -it mynginx2 bash

  哎?是不是跟最開始的例子有點類似,是的,沒錯,再重複之前的步驟下載安裝,ping。沒了。。。就這麼簡單。另外呢,假設你啟動容器的時候沒有指定網路,那麼也可以在後續通過connect命令來指定網路:

docker run -d --name mynginx3   nginx
docker network connect  myweb mynginx3
docker network disconnect myweb mynginx3

  當然,我們建立了網路之後,也可以通過命令來刪除自定義的網路:

docker network rm myweb

四、Compose

  Compose通過一個配置檔案來管理多個容器。在compose的配置檔案中通過services來定義,然後使用docker-compose指令碼來啟動、停止和重啟應用和應用中的服務以及所有依賴服務的容器。

  下面我們先來安裝下compose:

curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.4/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

  然後檢視下版本:

docker-compose -version

  這樣就安裝好了。

  然後,隨便找個地方建立個目錄,再建立個docker-compose.yml檔案。

 

   然後,編輯yml配置檔案,要注意的是yml有一套自己的規則,它是一個專門用來寫配置檔案的語言,這個大家可以百度去了解詳細的規則,這裡就不多說了,網上也有一些js轉yaml的工具,我們下面compose配置如下:

version: '2'
services:
  nginx1:
    image: nginx
    ports:
      - "8080:80"
  nginx2:
    image: nginx
    ports:
      - "8081:80"

  然後,我們來學習一些docker-compose的命令:

命令服務
docker-compose up 啟動所有的服務
docker-compose up -d 後臺啟動所有的服務
docker-compose ps 列印所有的容器
docker-compose stop 停止所有服務
docker-compose logs -f 持續跟蹤日誌
docker-compose exec nginx1 bash 進入nginx1服務系統
docker-compose rm nginx1 刪除服務容器
docker network ls 檢視網路網路不會刪除
docker-compose down 刪除所有的網路和容器

  然後,我們就可以通過docker-compose命令去啟動剛才配置的容器了:

docker-compose up

  怎麼驗證呢,再開啟個終端視窗,curl你啟動的ip就好了。之前玩過很多次了。然後,類似於之前的例子,我們也可以進入到剛剛通過docker-compose啟動的nginx容器中:

 

   然後,可以跟之前的遊戲一樣,安裝依賴,ping [nginx2'ip]。沒啥意思,都一樣。當然,類似於docker,我們也可以通過docker-compose命令,指定容器的網路和資料卷,區別的是,檔案的儲存位置不太一樣,docker-compose資料卷儲存在:/var/lib/docker/volumes/nginx-compose_data/_data中。我們來按照下面的配置引數配置一下:

version: '3'
services:
  nginx1:
    image: nginx
    ports:
      - "8081:80"
    networks:
      - "newweb"
    volumes:
      - "data:/data"
      - "./nginx1:/usr/share/nginx/html"
  nginx2:
    image: nginx
    ports:
      - "8082:80"
    networks:
      - "default"
    volumes:
      - "data:/data"
      - "./nginx2:/usr/share/nginx/html"
  nginx3:
    image: nginx
    ports:
      - "8083:80"
    networks:
      - "default"
      - "newweb"
    volumes:
      - "data:/data"
      - "./nginx3:/usr/share/nginx/html"
networks:
  newweb:
    driver: bridge
volumes:
  data:
    driver: local

  然後呢,類似之前的資料卷那章的測試方式:

docker exec nginx-compose_nginx1_1  bash
cd /data 
touch 1.txt
exit
cd /var/lib/docker/volumes/nginx-compose_data/_data
ls

  一樣的,一點意思都沒有,一個理解了,換個工具,核心思路都是一樣的。

  

 五、實踐

  基本上docker的內容我們就差不多學完了,下面我們來看下,如果建立一個node專案。我們先來看下目錄結構,注意,這個專案在你本地建立,然後通過ftp傳到伺服器上即可:

├── docker-compose.yml
└── images
    ├── nginx
    │   └── config
    │       └── default.conf
    └── node
        ├── Dockerfile
        └── web
            ├── package.json
            ├── public
            │   └── index.html
            └── server.js

  資料夾及檔案的內容就不說了哈,都能看得懂哦。然後呢,我們來看下各檔案的程式碼:

default.conf:

upstream backend {
    server node:3000;
}
server {
    listen 80;
    server_name localhost;
    root /public;
    index index.html index.htm;

    location /api {
        proxy_pass http://backend;
    }
}

package.json:

{
    "scripts": {
        "start": "node server.js"
        },
    "dependencies": {
        "mysql": "^2.16.0"
    }
}

server.js:

let http=require('http');
var mysql  = require('mysql');
var connection = mysql.createConnection({
  host     : 'db',
  user     : 'zfpx',
  password : '123456',
  database : 'node'
});

connection.connect();

let server=http.createServer(function (req,res) {
    connection.query('SELECT 2 + 2 AS solution', function (error, results, fields) {
        if (error) throw error;
        res.end(''+results[0].solution);
    });
});
server.listen(3000);

Dockerfile:

FROM node
COPY ./web /web
WORKDIR /web
RUN npm install
CMD npm start

docker-compose.yml:

version: '2'
services:
 node:
  build:
    context: ./images/node 
    dockerfile: Dockerfile
  depends_on: 
   - db
 web:
  image: nginx
  ports:
   - "8080:80"
  volumes:
   - ./images/nginx/config:/etc/nginx/conf.d
   - ./images/node/web/public:/public  
  depends_on:
   - node
 db:
  image: mariadb
  environment:
   MYSQL_ROOT_PASSWORD: "root"
   MYSQL_DATABASE: "node"
   MYSQL_USER: "zfpx"
   MYSQL_PASSWORD: "123456"
  volumes:
    - db:/var/lib/mysql
volumes:
 db:
  driver: local

  然後,把整個專案通過ftp傳到伺服器,在伺服器的nodeapp目錄下執行docker-compose up命令。如果啟動失敗了,別忘了是不是埠號被佔用了。啟動成功後,我們開啟另外一個命令終端,curl訪問地址即可。

  這個node例子跑不起來,後面再詳細搞。

 

相關文章