一、製作DockerFile
docker的映象類似於用一層一層的檔案組成。inspect命令可以檢視映象或容器的的資訊,其中Layers就是映象的層檔案,只讀不能修改,基於映象建立的容器會共享這些層。下面我們先來學習一下dockerFile中的一些命令:
- form,構建的新映象是基於哪個映象
- form centos:6
- maintainer,映象維護者姓名或郵箱地址。
- maintainer zaking。
- run,構建映象時執行的shell命令。
- RUN yum install httpd
- cmd,設定容器啟動後預設執行的命令及其引數,但cmd能夠被docker run後面的命令及引數替換。cmd給出的是一個容器的預設的可執行體。也就是容器啟動以後,預設的執行的命令。重點就是這個"預設"。意味著,如果
docker run
沒有指定任何的執行命令或者dockerfile
裡面也沒有entrypoint
,那麼,就會使用cmd指定的預設的執行命令執行。同時也從側面說明了entrypoint
的含義,它才是真正的容器啟動以後要執行命令。- CMD /usr/sbin/sshd -D
- CMD /usr/sbin/sshd -D
- expose,宣告容器執行的埠。
- EXPOSE 80 443
- env,設定容器內的環境變數。
- ENV MYSQL_ROOT_PASSWORD 123456
- add,拷貝檔案或目錄到映象中,如果是URL或者壓縮包會自動下載和解壓。
- ADD ,ADD https://xxx.com/html.tar.gz /var/www.html, ADD html.tar.gz /var/www/html
- copy,拷貝檔案或目錄到映象。
- COPY ./start.sh /start.sh
- entrypoint,配置容器啟動時執行的命令。
- ENTRYPOINT /bin/bash -c '/start.sh'
- volume,指定容器掛載點到宿主自動生成的目錄或其它容器。
- VOLUME ["/var/lib/mysql"]
- user,為 RUN CMD和ENTRYPOINT執行命令指定執行使用者。
- USER zaking
- workdir,為RUN CMD ENTRYPOINT COPY ADD 設定工作目錄。
- WORKDIR /data
- healthcheck,健康檢查。
- HEALTHCHECK --interval=5m --timeout=3s --retries=3 CMS curl -f htp://localhost
- 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例子跑不起來,後面再詳細搞。