在看了無數篇的博客以後,小編終於決定啃一啃docker的官方文檔,這裏不是說,其餘博主的博客毫無做用,而是,在有必定的docker基礎以後,纔有能力去挑戰一下純英文的官方文檔。
經過閱讀官方文檔,確實多docker的瞭解更加深刻,這裏小編主要爲你們介紹一下「get-started」,具體說了些什麼,能夠實現什麼,讓你們對docker有更深入的瞭解。
最後,小編仍是要誇一下官方文檔,確實讀了官檔以後,簡直對docker的瞭解面目一新,雖然知道了這麼多docker的命令和基礎知識,可是就好像如今的「快船」,沒有保羅這個線,果真只是各自綻開光芒的珍珠,總體實力不行啊!小編相信有了官方文檔這個線,必定能把docker的知識點都串起來。
固然上一篇文章是總體的給你們介紹一下docker的使用和基本配置,僅僅處於單機版,如今這個科技爆棚、大數據吹捧的時代,沒有分佈式,一切都毫無心義,小編經過官檔的part1-part6的研讀,向你們介紹一下關於docker的分佈式的部署和優勢,讓你們對docker有更更深刻的瞭解,固然仍是爲k8s打基礎,好了廢話不說了,擼文檔。
官方文檔地址:https://docs.docker.com/get-started/
這裏詳細的告訴咱們,經過閱讀這個基礎入門,咱們大致上能夠學習到:
- Part1:如何設置本身的docker環境
- Part2:構建一個image並做爲容器運行
- Part3:擴展應用程序以運行多個容器(這裏的擴展表示的是一個容器的多個副本)
- Part4:跨集羣的分佈式應用程序(docker的分佈式)
- Part5:經過後端數據庫來堆棧服務
- Part6:將應用程序上線到生產html
Part1主要是對docker的概念作了解,並列出了一些docker的基礎命令,告訴咱們docker是什麼、docker的優點以及docker的下載和安裝。
這裏小編就不在介紹docker如何安裝,介紹一些docker的常見命令:前端
#查看docker的版本 docker --version #查看docker的詳細信息 docker info #使用docker運行一個容器 docker run hello-world #查看docker已下載的images docker image ls #查看全部的容器(運行的和已退出的) docker container ls --all
通過part1的介紹和對docker的理解,在part2中咱們也能夠構建本身的應用程序,可是這裏構建的應用程序只是最底層的使用一個container去構建,以後會介紹service級別的和堆棧級別的(用於生產)。node
這裏在構建一個應用程序時,體現了docker的一個優點—隔離,也就是說,若是你的應用在以後的升級和更新以後會變得很大,底層依賴的環境會愈來愈多,當這個應用程序大到能夠左右你的系統時,那麼若是須要對這個應用程序進行遷移或者在這個系統上部署其餘的服務,對運維來講簡直就是一個災難。這時候docker的強大之處就體現出來了,docker能夠保證每個container是徹底隔離的,不一樣的應用放置在不一樣的container中,若是想要遷移這個服務,只須要將這個container構建成一個image,並上傳到本身的registry中(企業級的使用harbor),就能夠在任意地方,pull這個image,以後運行便可。
官網給出了這樣的一個例子:過去,若是要開始編寫Python應用程序,首先要作的就是在機器上安裝Python運行時。可是,這就形成了這樣一種狀況:您的機器上的環境須要根據您的應用程序去部署,以便您的應用程序可以按預期運行,並且還須要與您的生產環境相匹配。使用Docker,您只須要獲取一個可移植的Python運行時做爲映像,不須要安裝。而後,只須要在這個有python環境基礎的images上部署你的代碼和依賴,他就能夠正確的運行你的應用程序。最終這些可移植的image由dockerFile構建。
接下來經過一個實戰案例去解釋上面這段話的含義:python
#Use an official Python runtime as a parent image FROM python:2.7-slim #Set the working directory to /app WORKDIR /app #Copy the current directory contents into the container at /app COPY . /app #Install any needed packages specified in requirements.txt RUN pip install --trusted-host pypi.python.org -r requirements.txt #Make port 80 available to the world outside this container EXPOSE 80 #Define environment variable ENV NAME World #Run app.py when the container launches CMD ["python", "app.py"]
這裏這個dockerfile出現了兩個文件須要本身編寫:app.py and requirements.txtnginx
#app.py from flask import Flask from redis import Redis, RedisError import os import socket # Connect to Redis redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2) app = Flask(__name__) @app.route("/") def hello(): try: visits = redis.incr("counter") except RedisError: visits = "<i>cannot connect to Redis, counter disabled</i>" html = "<h3>Hello {name}!</h3>" \ "<b>Hostname:</b> {hostname}<br/>" \ "<b>Visits:</b> {visits}" return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(), visits=visits) if __name__ == "__main__": app.run(host='0.0.0.0', port=80)
#requirements.txt Flask Redis
注意:dockerfile、app.py 、 requirements.txt在同一個目錄下。web
#構建並運行容器:
#構建images
docker build -t --tag=friendlyhello .
#查看構建的image
$ docker image ls
#運行image的容器
docker run -p 4000:80 friendlyhello
若是順利的話,就能夠在http://localhost:4000中看見以下界面:
到這裏,一個基於dockerfile的容器就這樣構建好,並運行起來了,是否是很是的簡單。redis
在part2中咱們只是使用dockerfile構建一個image,而且經過image運行了container,在part3中咱們將實現分佈式應用服務的一個特性--load-balancing,這就不得不將剛剛的container上升一個高度到:service。
在分佈式應用程序中,應用程序的不一樣部分稱爲「服務」。例如,若是您設想一個視頻共享站點,它可能包括一個用於在數據庫中存儲應用程序數據的服務、一個用於用戶上傳內容後在後臺進行視頻代碼轉換的服務、一個用於前端的服務,等等。
服務實際上只是「生產中的容器」。「一個服務只運行一個映像,可是它將映像運行的方式進行了編碼——應該使用什麼端口,應該運行多少個容器副本,以便服務具備所需的容量,等等。擴展服務能夠改變運行該軟件的容器實例的數量,從而爲流程中的服務分配更多的計算資源。
這裏咱們就着手去構建一個本身的services:
#編寫一個docker-compose.yml文件:
#Yml是一個yaml文件,它定義了Docker容器在生產環境中的行爲。docker
version: "3" services: web: # replace username/repo:tag with your name and image details image: nginx deploy: replicas: 5 resources: limits: cpus: "0.1" memory: 50M restart_policy: condition: on-failure ports: - "4000:80" networks: - webnet networks: webnet:
這個文件告訴了docker須要作的事情:shell
使用默認設置定義webnet網絡(這是一個負載平衡的覆蓋網絡)數據庫
#設置節點爲集羣管理器
docker swarm init
#運行本身的負載均衡app
docker stack deploy -c docker-compose.yml getstartedlab
注意:這裏「getstartedlab」是給本身的service起一個名字
#查看全部的service
docker service ls
#查看具體的service
docker stack services getstartedlab
能夠看到這個service中運行了5個副本,而其名稱爲「getstartedlab_web」
#咱們在查看getstartedlab_web下的task
docker service ps getstartedlab_web
docker stack ps getstartedlab #這種方式也能夠獲取service的容器的運行狀態
注意:這裏的一個單一的container在service中稱爲task,每個container在service有一個惟一的ID,以數字的形式順序遞增。
#同理咱們查看docker的容器,一樣能夠看見這個五個task
[root@zy dockerfile]# docker ps
此時在瀏覽器中輸入http://localhost:4000,就能看見以下界面:
補充:
#刪除服務 docker stack rm getstartedlab #取消這個節點爲集羣的管理節點 docker swarm leave --force
這一部分介紹的是,將應用程序部署到集羣中去,並在多臺機器上運行。多容器、多機器的應用程序能夠經過將多臺機器鏈接到一個叫「Dockerized」集羣中來實現。
Swarms 是一組運行docker並加入到集羣的機器。在Swarms中運行的docker命令,都將由集羣管理器執行,集羣中的機器能夠是物理機也能夠是虛擬機。一旦加入到了Swarms中它們就被稱爲一個節點。
集羣的管理器可使用不一樣的策略去運行容器。如「emptiest node」 表示:用容器填充利用率最低的容器;或者「global」表示:確保每臺機器只得到指定容器的一個實例。指示集羣管理器在編排文件中使用這些策略,就像已經使用的策略同樣。
Swarms的集羣管理器是惟一可以執行命令的機器。他能夠受權其餘的機器做爲worker加入集羣,worker只提供生產能力,沒有權利指示其餘的機器該作什麼和不應作什麼。
集羣是由多個節點組成的,能夠是物理機也能夠是虛擬節點。其基本概念比較簡單:運行docker swarm init 以啓用集羣模式,並使當前正在使用的機器成爲一個集羣管理器,而後在其餘機器上運行docker swarm join讓他們做爲worker加入到集羣中。這裏咱們使用的是vm快速建立一個雙機集羣。
#建立兩個虛擬節點 #這裏使用docker-machine,以VirtualBox 驅動建立兩個虛擬節點: $docker-machine create --driver virtualbox myvm1 $docker-machine create --driver virtualbox myvm2
注意:Docker-machine是 Docker 官方提供的一個工具,它能夠幫助咱們在遠程的機器上安裝 Docker,或者在虛擬機 host 上直接安裝虛擬機並在虛擬機中安裝 Docker。
https://docs.docker.com/machine/install-machine/ 官網的安裝docker-machine。
#查看這兩個虛擬機的IP docker-machine ls
注意:這裏的默認端口是2376,若是系統中有進程佔用了2376,會報錯。
#初始化集羣並添加節點 #以myvm1爲管理節點,執行管理命令並驗證myvm2是否加入集羣,myvm2是一個從節點。 $ docker-machine ssh myvm1 "docker swarm init --advertise-addr <myvm1 ip>"
注意:若是這裏出現了問題,使用--native-ssh 使用系統的ssh
docker-machine --native-ssh ssh myvm1 ...
#添加myvm2做爲工做節點 $ docker-machine ssh myvm2 "docker swarm join \ --token <token> \ <ip>:2377"
到這裏,就建立好了屬於本身swarm的集羣。
#查看集羣的節點 $ docker-machine ssh myvm1 "docker node ls"
#運行docker-machine env myvm1得到命令,將shell配置爲與myvm1對話: $ docker-machine env myvm1 export DOCKER_TLS_VERIFY="1" export DOCKER_HOST="tcp://192.168.99.100:2376" export DOCKER_CERT_PATH="/Users/sam/.docker/machine/machines/myvm1" export DOCKER_MACHINE_NAME="myvm1" # Run this command to configure your shell: # eval $(docker-machine env myvm1)
注意:這句話表示當前的shell鏈接myvm1。(也就是在這個shell的操做實際上實在myvm1中的)
#運行給定的命令,將shell配置爲與myvm1對話 eval $(docker-machine env myvm1)
#查看myvm1是否active,*號表示成功 $ docker-machine ls
在swarm管理節點上部署app docker stack deploy -c docker-compose.yml getstartedlab
注意:雖說這個shell是在myvm1中的,可是隻要咱們的所在位置是docker-compose.yml的文件所在位置,那麼仍然可使用docker-compose.yml文件。
#若是鏡像不是在docker Hub,而是在本身的私服上,可使用docker login 登陸 $docker login registry.example.com $docker stack deploy --with-registry-auth -c docker-compose.yml getstartedlab
#查看stack中運行的container $ docker stack ps getstartedlab
注意:注意這裏在集羣的各個節點上都有運行,而且在訪問時時隨機的指定哪個container提供服務,實現了負載均衡。
固然使用虛擬機的IP,去查看:
這兩個IP地址都能工做的緣由是羣中的節點參與了一個入口路由網格。這能夠確保部署在集羣中某個端口的服務始終保留該端口,無論實際運行容器的是哪一個節點。上面是一個圖,展現了一個名爲my-web的服務的路由網格是如何在一個三節點羣上的8080端口發佈的。
狀況一:經過改變docker-compose.yml 文件去擴展應用程序。
狀況二:改變應用程序的行爲和代碼以後,構建出一個新的image,而且push的倉庫中。
以上的兩種狀況只須要docker-compose.yml file 從新構建service便可。
固然若是,swarm集羣中加入了新的節點,此時,只須要在這個新的節點上執行docker swarm join 將這個節點加入到swarm集羣中,以後的 docker stack deploy 操做會自動的利用新的資源(新加入的節點)。
#拆除stack docker stack rm getstartedlab #移除整個swarm集羣 鏈接每個worker節點執行: docker-machine ssh 節點名 "docker swarm leave" #在每一個節點上取消以前的環境變量: eval $(docker-machine env -u) #重啓docker machines docker-machine start <machine-name>
在part4部分中,學習瞭如何設置一個運行docker容器的集羣,並將一個應用程序部署到其中,容器在多臺機器上同時運行。
在part5將介紹分佈式應用程序層次中的頂層:堆棧。堆棧是一組互相關聯的服務,他們共享依賴關係,而且能夠在一塊兒編排和伸縮,單個堆棧可以定義和協調整個應用程序的功能(很是複雜的應用程序須要使用多個堆棧)。
其實在part3中就使用了堆棧,當在撰寫一個Compose 文件時就是使用的堆棧deploy,可是在單個主機上運行的單個服務堆棧,這個通常在生產環境中不會出現,在part5中可使多個服務彼此關聯,並在多臺機器上運行。
添加新服務很簡單,使用Compose.yml文件便可。這裏咱們添加一個免費的visualizer服務,他容許咱們查看集羣如何調度容器、服務額部署。
#docker- composition.yml: version: "3" services: web: # replace username/repo:tag with your name and image details image: nginx deploy: replicas: 5 restart_policy: condition: on-failure resources: limits: cpus: "0.1" memory: 50M ports: - "80:80" networks: - webnet visualizer: image: dockersamples/visualizer:stable ports: - "8080:8080" volumes: - "/var/run/docker.sock:/var/run/docker.sock" deploy: placement: constraints: [node.role == manager] networks: - webnet networks: webnet:
這裏咱們建立了兩個服務,nginx和visualizer。而且使用了volumes,提供了本機映射docker的目錄文件。而且添加了一個放置鍵,保證了服務只能在docker的管理節點上運行,而不是在worker上運行。
#確保shell配置爲與myvm1對話 $eval $(docker-machine env myvm1)
#在管理節點上從新運行docker stack deploy命令,任何須要更新的服務都會更新: $ docker stack deploy -c docker-compose.yml getstartedlab
經過docker-machine ls得到其中一個節點的IP地址。去任何一個IP地址的8080端口均可以看見:
此時能夠看見visualizer單一副本的服務在管理節點上運行,而且web的5個實例分散在集羣中。能夠經過docker stack ps <stack>,來驗證:
$docker stack ps getstartedlab
visualizer是一個獨立的服務,能夠在任何包含在堆棧中的應用程序中運行。它不依賴於其餘任何東西。如今讓咱們建立一個具備依賴性的服務:提供訪問者計數器的Redis服務。
#docker-compose.yml: version: "3" services: web: # replace username/repo:tag with your name and image details image: nginx deploy: replicas: 5 restart_policy: condition: on-failure resources: limits: cpus: "0.1" memory: 50M ports: - "80:80" networks: - webnet visualizer: image: dockersamples/visualizer:stable ports: - "8080:8080" volumes: - "/var/run/docker.sock:/var/run/docker.sock" deploy: placement: constraints: [node.role == manager] networks: - webnet redis: image: redis ports: - "6379:6379" volumes: - "/home/docker/data:/data" deploy: placement: constraints: [node.role == manager] command: redis-server --appendonly yes networks: - webnet networks: webnet:
redis在鏡像庫中有一個官方的鏡像,命名就是Redis,最重要的是,在Redis規範中有兩件事可讓數據在這個堆棧的部署之間持久:
#在管理機器上建立一個/data目錄 $docker-machine ssh myvm1 "mkdir ./data" #保證當前shell在myvm1: $eval $(docker-machine env myvm1) #更新堆棧: $ docker stack deploy -c docker-compose.yml getstartedlab #查看服務 $ docker service ls #查看IP $docker-machine ls
#驗證:
驗證nginx在任意節點上訪問nginx:
#查看visualizer 服務:
檢查一個節點的web頁面,例如http://192.168.130.101,並查看訪問者計數器的結果,該計數器如今是活動的,並在Redis上存儲信息。
總結:棧是相互關聯的服務,而且全部的服務是同步運行的。使用位置約束和數據卷,能夠將容器中的數據持久化到本地主機中,所以當容器被從新部署的時候,應用程序的數據不會丟失。
最終part6總結了dockerized應用程序的一些選項:
#建立本身的swarm在node上 docker swarm init #部署本身的app docker stack deploy -c docker-compose.yml getstartedlab #查看本身swarm的node $ docker node ls #查看服務列表 $ docker service ls #查看具體服務下的容器 $ docker service ps vy7n2piyqrtr #刪除一個堆棧 docker stack rm getstartedlab