Docker 是一個開源的應用容器引擎,基於Go 語言並聽從 Apache2.0 協議開源。
Docker 可讓開發者打包他們的應用以及依賴包到一個輕量級、可移植的容器中,而後發佈到任何流行的 Linux 機器上,也能夠實現虛擬化。html
這裏可移植指的是,能夠直接將鏡像保存爲鏡像壓縮文件,而後能夠將這個鏡像壓縮文件發送到任何一臺機器上從新加載成鏡像,而後根據該鏡像建立容器便可完成移植。vue
容器是徹底使用沙箱機制,相互之間不會有任何接口(相似 iPhone 的 app),更重要的是容器性能開銷極低。node
沙箱是一個虛擬系統程序,沙箱提供的環境相對於每個運行的程序都是獨立的,並且不會對現有的系統產生影響。ios
沙箱具備很是良好的獨立性、隔離性,因此可以搭建一些具備高風險的軟件進行測試。好比,你能夠在沙箱裏面運行一個病毒程序,也是安全的。nginx
Docker容器應用場景:web
Docker容器的優勢:redis
鏡像至關因而一個root文件系統,能夠理解成一個軟件安裝包。好比nginx鏡像,有了nginx鏡像文件,就至關於有了nginx軟件安裝包,咱們就能夠對nginx進行安裝運行了。docker
容器至關因而一個鏡像運行的環境,能夠理解爲咱們的電腦操做系統。因此咱們能夠將咱們的鏡像文件安裝到咱們的容器中,當咱們啓動容器的時候,能夠經過指定CMD在容器運行後所要執行的命令,來運行咱們的鏡像。數據庫
倉庫,用於保存鏡像的一個倉庫,有本地鏡像倉庫和官方的遠程鏡像倉庫(Docker Hub),相似於代碼提交的倉庫,咱們能夠從遠程鏡像倉庫下載鏡像到本地,也能夠將本地建立的鏡像推送到遠程倉庫中。express
① 鏡像的基礎操做
咱們要建立容器必需要基於鏡像。當咱們安裝好Docker以後,咱們就能夠直接在終端中經過docker命令從遠程鏡像倉庫(Docker Hub)進行鏡像的下載,下載無需登陸便可Docker 帳號,只有將本地鏡像推送到Docker Hub才須要登陸。
docker search image_name
// 搜索nginx鏡像資源 docker search nginx
// 搜索官方發佈的ngnix鏡像 docker search --filter "is-official=true" nginx // 搜索自動化發佈的鏡像 docker search --filter "is-automated=true" nginx // 搜索星星數量在2000以上的鏡像 docker search --filter "stars=2000" nginx
// 從遠程Docker Hub中下載nginx鏡像 docker pull nginx
// 查看本地倉庫中有哪些鏡像 docker images
// 從本地倉庫中刪除nginx鏡像 docker rmi nginx // 從本地倉庫中強制刪除vuenginx鏡像 docker rmi -f vuenginx
// 將docker中的vuenginx鏡像導出到宿主機上 docker save -o vuenginx.tar vuenginx
-o即--output,指定保存後的鏡像名稱,以後的參數爲docker中要被導出的鏡像名
// 加載宿主主機當前目錄下的images目錄下的名爲vuenginx的鏡像壓縮包 docker load -i ./images/vuenginx.tar
須要注意的是,壓縮包的名稱並不會影響加載後鏡像的名稱,即鏡像保存的時候是基於哪一個鏡像,加載後顯示的也是哪一個鏡像。
// 基於宿主機上./images/vuenginx.tar鏡像壓縮包導入到docker中並命名爲test docker import ./images/vuenginx.tar test
注意,鏡像名稱必須全小寫。
兩者的區別:
docker import:丟棄了全部的歷史記錄和元數據信息,僅保存容器當時的快照狀態。在導入的時候能夠從新制定標籤等元數據信息。
docker load:將保存完整記錄,體積較大。
② 容器的基礎操做
有了鏡像,咱們就能夠基於鏡像來建立、運行容器了。
// 基於nginx鏡像建立名爲nginxContainer容器 docker create --name nginxContainer nginx docker create --name "nginxContainer" nginx docker create --name=nginxContainer nginx docker create --name="nginxContainer" nginx
--name指定容器名稱的時候,以上四種方式均可以。經過created命令建立的容器會處於Created狀態,同名的容器不能重複建立。
// 從新啓動、運行指定的容器 docker restart nginxContainer
運行的容器會處於Up狀態。
docker run -itd --name=container_name image_name
-i 表示以交互模式運行容器,一般與-t同時使用;
-t 表示爲容器從新分配一個僞輸入終端,一般與-i同時使用;
-d 表示後臺運行容器,並返回容器ID
--name 爲容器指定名稱,同create命令,若是沒有指定名稱,那麼docker爲建立的容器自動生成一個名稱。
// 基於nginx容器建立並運行容器 docker run nginx docker run -i nginx docker run -t nginx docker run -it nginx
以上四個命令執行後終端會停住沒法輸入,由於容器在前臺運行,而且因爲沒有經過--name指定,因此建立的容器名由docker自動生成,結束終端以前,建立的容器會一直處於運行狀態,結束終端後容器會當即進行中止狀態。
// 基於nginx容器建立並運行名爲nginxContainer的容器 docker run -itd --name nginxContainer nginx
以上命令執行後,終端會當即返回容器的id,而且容器在後臺運行,此時終端能夠繼續輸入,而且容器也處於運行狀態。
在run容器的時候,還能夠傳遞一個COMMAND,即在容器運行起來以後執行指定的命令,而且這個命令會影響建立的容器的狀態。
若是這個命令是能夠持續運行的,那麼容器也能夠進入到運行狀態。
若是這個命令是執行完成後就結束的,那麼容器也會隨着命令的結束而進入中止狀態。
也就是說,若是想讓建立的容器處於一直運行狀態,那麼咱們必須在容器啓動後執行一個可持續運行的命令。如:
# 容器基於nginx鏡像建立並啓動而且容器啓動後執行 echo "hello docker"命令 docker run -itd --name test nginx echo "hello docker"
因爲容器啓動後執行的命令是執行完成後就結束的命令,因此建立的test容器也隨之進入中止狀態。
# 容器基於nginx鏡像建立並啓動而且容器啓動後執行 sleep 10 docker run -itd --name test nginx sleep 10
因爲容器啓動後執行的命令是能夠持續執行10秒的命令,因此建立的test容器會運行10秒後再進入中止狀態。
// 查看運行中的容器信息 docker ps // 查看全部容器信息包括已經中止運行的 docker ps -a // 查看運行中的容器信息 docker container list // 查看全部容器信息包括已經中止運行的 docker container list -a
根據命令輸出結果,咱們能夠看到容器id只顯示了一部分,而咱們的容器id的值實際上是一個64位的字符串,若是咱們想要完整的顯示出來,能夠加上--no-trunc
參數,如:
# 查看容器各字段詳細信息 docker ps -a --no-trunc
// 中止正在運行的名爲nginxContainer的容器 docker stop nginxContainer
// 從新運行的名爲nginxContainer的容器 docker restart nginxContainer
// 刪除已經中止運行的名爲nginxContainer的容器,若是該容器還在運行,必須先stop掉,再刪 docker rm nginxContainer
// 進入容器的終端界面,其實就是在容器中執行了bash命令 docker exec -it nginxContainer bash
須要注意的是,必須帶上-i和-t,-t只能進入到容器的終端界面,但沒法進行命令交互,-i只可以進行命令交互,可是沒有終端界面,不是很好用,因此-it才能進行正常命令交互。
// 提交nginxContainer容器上的修改,而且將提交而產生的鏡像命名爲new_nginxontainer docker commit -m "create a new image" nginxContainer new_nginxontainer
# 將vueApp這個容器進行導出而且保存爲vueApp.tar鏡像壓縮包 docker export vueApp > vueApp.tar
# 將vueApp.tar鏡像壓縮包導入並保存爲鏡像,名字爲vueappimage docker import vueApp.tar vueappimage # 同一個鏡像能夠被導入保存爲鏡像屢次 docker import vueApp.tar vueappimage2
③ 容器的進階操做
容器的進階操做,主要是指docker容器和宿主機之間端口、文件的綁定,實現宿主機中修改可以當即同步到docker容器中。
// 將宿主機的8080端口與docker的80端口進行映射 docker run -itd --name nginxContainer -p 8080:80 nginx
此時瀏覽器地址欄中輸入http://localhost:8080/,請求就會被轉發到docker的80端口上,就能查看到nginx提供的默認首頁了
// 將宿主主機下指定目錄與docker容器目錄進行關聯 docker run -itd --name vueApp -p 8080:80 -v /**/**/test-docker/dist:/usr/share/nginx/html/ vuenginx
須要注意是,本地宿主主機目錄必須是絕對路徑,而且若是宿主主機上該目錄文件發生變化,那麼須要執行restart命令重啓容器纔會生效。
此時本地宿主主機中的目錄和容器中的目錄就被關聯起來了,關聯目錄下本地文件一旦被修改,用戶再次訪問頁面的時候就會顯示修改過的頁面了。
// 將容器中的/etc/nginx/conf.d/default.conf文件拷貝到宿主主機的/**/**/target_dir/目錄中 docker cp nginxContainer:/etc/nginx/conf.d/default.conf /**/**/target_dir/ // 將宿主主機中的/www/index.html 拷貝到容器的/usr/share/nginx/html/ 目錄下 docker cp /www/index.html nginxContainer:/usr/share/nginx/html/
Dockerfile是一個用來構建鏡像的文本文件,文本內容包含了一條條構建鏡像所需的指令和說明。
Dockerfile文件結構通常分爲四部分,基礎鏡像信息、維護者信息 鏡像操做指令和容器啓動時執行的指令,dockerfile文件中能夠經過#號進行註釋。
指令詳解
# 以nginx鏡像爲基礎進行構建 FROM nginx
# lihb維護該dockerfile文件 MAINTAINER lihb
# 執行命令安裝項目所需依賴 RUN npm install
dockerfile的指令每執行一次都會在docker上新建一層。因此過多無心義的層,會形成鏡像膨脹過大。
FROM centos RUN yum install wget RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" RUN tar -xvf redis.tar.gz # 以上執行會建立3層鏡像。可簡化爲如下格式: FROM centos RUN yum install wget \ && wget -O redis.tar.gz"http://download.redis.io/releases/redis-5.0.3.tar.gz" \ && tar -xvf redis.tar.gz
上面的僅表示換行,若是命令短的話,其實能夠不須要換行,可是換行必須加上斜槓。
# 不換行寫法 FROM nginx RUN echo "test" && pwd && ls
# dockfile文件所在目錄下的dist目錄下的全部文件添加到docker容器中指定目錄下 COPY dist/ /usr/share/nginx/html/ COPY nginx/default.conf /etc/nginx/conf.d/default.conf
COPY指令中,宿主主機上的目錄必須是相對於構建時所用的dockerfile所在的目錄。
相同功能下,建議使用COPY。
# 執行命令安裝項目所需依賴 RUN npm install # 執行npm start腳本 CMD ["npm", "start"]
ENTRYPOINT ["nginx", "-g", "daemon off;"]
ENV PATH /usr/local/nginx/sbin:$PATH # 後續的指令中能夠經過 $NODE_VERSION 引用 ENV NODE_VERSION 7.2.0
# 聲明容器可使用80和443端口 EXPOSE 80 443
# 容器運行時,會建立一個/foo目錄 VOLUME /foo
# 至關於執行了cd /usr/src/docker-server WORKDIR /usr/src/docker-server
ARG NGINX_VERSION=1.15.0
經過dockerfile文件構建鏡像
能夠經過docker build 命令進行鏡像的構建,-f指定dockerfile文件的路徑,-t指定構建好的鏡像名稱,最後加一個.
// 千萬不要少了最後面的那個點 docker build -f /path/to/dockerfile -t image_name .
dockerfile文件的名稱或後綴能夠任意,只要裏面的指令正確就行。若是沒有經過-f指定dockerfile文件的路徑,那麼默認會找當前終端所在目錄下的dockerfile文件,沒有則構建失敗。
① 經過Vue CLI建立Vue項目
這一步比較簡單,直接經過vue create 命令建立便可,如:
# 建立一個名稱爲test-docker的項目 vue create test-docker # 進入到test-docker項目根目錄 cd test-docker # 構建vue項目 npm run build
執行完npm run build
後,會在項目根目錄下建立一個dist目錄,裏面存放的就是vue項目打包後的結果,用於生產發佈。咱們只須要將dist目錄中的內容部署到靜態資源站點就能夠直接訪問到該項目了。下面咱們將以nginx服務器爲例,在docker中建立一個nginx的容器來運行咱們的nginx服務器,同時將dist目錄中的內容放到nginx服務器的靜態資源站點下。
② 建立包含dist目錄中內容的nginx鏡像
這裏咱們以官方的nginx鏡像爲基礎,同時將dist目錄中的內容拷貝到nginx靜態資源站點下,並構建出一個新的鏡像,而後再根據這個新的鏡像去建立容器,那麼建立好的容器中就會帶上dist目錄下的內容。固然也在容器建立好以後再將dist中的目錄拷貝進去也是能夠的。
# 以官方的nginx鏡像爲基礎進行構建 FROM nginx # 將當前dockerfile所在目錄下的dist目錄的內容拷貝到容器的/usr/share/nginx/html/下 COPY dist/ /usr/share/nginx/html/
根據該dockerfile構建出帶有dist目錄內容的nginx鏡像。
# 進入到vue項目根目錄 cd /path/to/vue項目根目錄 # 構建鏡像,鏡像名爲vuenginx docker build -t vuenginx .
當咱們在vue項目根目錄下執行docker build命令的時候,docker會自動在當前目錄下尋找dockerfile文件,而後根據dockerfile文件中的指令進行鏡像的構建,構建出的鏡像名爲 -t指定的名稱,須要注意的是最後的點號不能少。
打開終端輸入如下命令檢查鏡像是否建立成功,如:
# 打開終端直接輸入如下命令 docker images | grep "vuenginx"
③ 建立並運行vueApp容器
建立好鏡像以後,咱們就能夠基於該鏡像建立並運行容器了,如:
# 基於vuenginx運行容器 docker run -itd --name vueApp -p 8080:80 vuenginx # 查看容器信息 docker ps -a
運行容器而且將本地主機的8080端口與容器的80端口綁定,當咱們在本地主機上訪問8080端口的時候,請求就會被轉發到容器的80端口上,從而被容器中的nginx服務器處理。
此時咱們在本地主機瀏覽器上訪問http://localhost:8080/,便可看到咱們的vue項目首頁了,說明咱們已經成功在docker容器中部署了一個靜態資源服務器。爲了可以讓咱們的vueApp可以發起異步請求數據,咱們還須要在docker中建立node服務器容器,提供web服務器功能。
④ 新建node應用做爲vue應用的web服務器
新建一個node項目,並在node項目根目錄下建立一個index.js做爲node應用啓動入口文件,以下:
# 建立docker-server目錄 mkdir docker-server # 初始化package.json文件 npm init --yes # 新建index.js文件
index.js內容以下
const express = require("express"); const app = express(); app.get("/docker", (req, res, next) => { res.send("hello, welcome to docker web server for vueApp."); }); app.listen(3000);
package.json內容以下:
{ "name": "docker-server", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "node index.js" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "express": "^4.17.1" } }
⑤ 建立nodeserver鏡像
這裏咱們以官方的node鏡像爲基礎,同時將node應用根目錄下的內容拷貝到鏡像中,並安裝項目依賴,並構建出一個新的鏡像,而後再根據這個新的鏡像去建立容器,那麼建立好的容器中就會帶上node應用的源碼了。
# 構建node鏡像 FROM node # 找一個目錄存放咱們的server代碼, 至關於執行了cd /usr/src/docker-server WORKDIR /usr/src/docker-server # 複製當前目錄內容 到容器中指定的應用根目錄下 COPY . . # 執行命令安裝項目所需依賴 RUN npm install # 讓容器可使用3000端口 EXPOSE 3000 # 容器啓動後執行npm start腳本 CMD ["npm", "start"]
這裏node_modules和dockerfile文件中的東西就不須要拷貝到鏡像裏去了,咱們直接在鏡像裏面安裝便可,能夠添加一個.dockerignore文件進行忽略,如:
# .dockerignore文件內容 node_modules npm-debug.log dockerfile Dockerfile
根據該dockerfile構建出帶有node應用node鏡像。
# 進入到docker-server項目根目錄 cd /path/to/docker-server項目根目錄 # 構建鏡像,鏡像名爲nodeserver docker build -t nodeserver .
⑥ 建立並運行vueServer容器
# 基於nodeserver建立並運行容器 docker run -itd --name vueServer -p 8888:3000 nodeserver
這裏將本地主機的8888端口與docker容器的3000端口進行了映射。
容器運行後,在本地主機訪問http://localhost:8888/test,檢測docker下的node服務器是否部署成功。
說明docker下的node服務器已經部署成功了,接下來咱們須要修改vue項目,讓其訪問這個node服務器。
⑦ 修改Vue項目
在HelloWorld.vue組件的created生命週期中添加一個向服務器異步獲取數據的接口,如:
# 安裝axios並引入 import axios from "axios" created() { axios.get("/api/docker").then((res) => { this.msg = res.data; }); }
如今咱們在本地主機訪問vue項目的時候,會發起http://localhost:8080/api/docker的請求,請求會被轉發到docker容器的80端口,即http://localhost/api/docker,可是咱們docker中的服務器是3000端口,因此須要進行跨域,因此咱們還要修改nginx的配置文件添加代理。
因爲vueApp和vueServer是在兩個不一樣的容器中,就至關因而在兩臺不一樣的電腦上,因此咱們不能再使用localhost進行請求轉發了,必須找到vueServer的ip地址,有兩種方式,如:
可知其ip地址爲172.17.0.2
在vue項目根目錄下新建一個nginx目錄,而後新建一個default.conf,配置文件內容以下:
server { listen 80; server_name localhost; access_log /var/log/nginx/host.access.log main; error_log /var/log/nginx/error.log error; location / { root /usr/share/nginx/html; index index.html index.htm; } location /api/ { rewrite /api/(.*) /$1 break; proxy_pass http://172.17.0.2:3000; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
此時咱們在本地主機修改後,重啓容器,發現修改並無應用咱們剛剛的修改,咱們還得按上面的步驟從新建立鏡像和容器,這樣顯然是很是麻煩,咱們能夠將本地主機的文件或目錄與docker容器中的文件或目錄進行掛載,這樣當本地主機修改後,容器重啓便可應用本地主機的修改。
# 中止並刪除以前的vueApp容器 docker stop vueApp docker rm vueApp # 從新建立運行容器並進行文件掛載綁定 docker run -itd --name vueApp -p 8080:80 \ --mount type=bind,source=/path/to/test-docker/dist,target=/usr/share/nginx/html \ --mount type=bind,source=/path/to/test-docker/nginx,target=/etc/nginx/conf.d \ nginx
固然咱們也能夠經過-v進行文件的掛載,如:
# 中止並刪除以前的vueServer容器 docker stop vueServer docker rm vueServer # 從新建立運行容器並進行文件掛載綁定 docker run -itd --name vueServer -p 8888:3000 \ -v /Users/banma-798/Documents/learn/docker-server:/usr/src/docker-server nodeserver
此時再次訪問http://localhost:8080,頁面以下顯示,表示跨域請求成功。
⑧ 配置負載均衡
爲了可以讓後端服務器可以處理更多請求,一般咱們會配置多臺服務器,以保證後端服務器的穩定,提升吞吐量和減小延遲,最大化資源利用率。因此咱們能夠再建立一個vueServer容器,如:
# 再次建立並運行一個node服務器,容器名爲vueServer2 docker run -itd --name vueServer2 -p 9999:3000 \ -v /Users/banma-798/Documents/learn/docker-server:/usr/src/docker-server nodeserver
此時咱們在本地主機上訪問http://localhost:9999/docker,若是請求成功表示第二臺服務器啓動成功。
查看新建的vueServer2的ip地址爲172.17.0.4
修改配置文件,以下:
upstream backend{ server 172.17.0.4:3000; server 172.17.0.2:3000 } location /api/ { rewrite /api/(.*) /$1 break; proxy_pass backend; }