目錄html
Docker已經上市不少年,不是什麼新鮮事物了,不少企業或者開發同窗之前也很少很多有所接觸,可是有實操經驗的人很少,本系列教程主要偏重實戰,儘可能講乾貨,會根據本人理解去作闡述,具體官方概念能夠查閱官方教程,由於本系列教程對前一章節有必定依賴,建議先學習前面章節內容。java
本系列教程導航:
Docker深刻淺出系列 | 容器初體驗
Docker深刻淺出系列 | Image實戰演練
Docker深刻淺出系列 | 單節點多容器網絡通訊
Docker深刻淺出系列 | 容器數據持久化
Docker深刻淺出系列 | 單機Nginx+Springboot實戰
Docker深刻淺出系列 | Docker Compose多容器實戰node
教程目的:mysql
1.克隆credit-facility-service
做爲後面部署演示使用,使用docker
分支linux
git clone https://github.com/EvanLeung08/credit-facility-service.git
2.虛擬機、centos和docker環境安裝請查看第一章,本章默認已經安裝好centos和docker
Docker深刻淺出系列 | 容器初體驗nginx
簡單來講,Docker Swarm就是一個把多個物理主機或者虛擬機組成的集羣上的容器羣進行管理的容器編排工具,負責編排、調度和集羣管理,由集羣的活動由集羣管理器控制,加入集羣的機器稱爲節點,容許用戶管理跨多個主機部署的多個容器。git
SwarmKit是可擴展分佈式系統的節點發現、基於Raft的共識、任務調度、基於基元的編排工具包,該工具包使用Raft共識算法來協調和決策分佈式系統。github
如下列出了Docker Swarm的一些關鍵術語:web
節點(Node): 在編排方面,節點是主機。 一個節點能夠是單個主機中的多個VM。算法
管理節點(Manager Node): 此節點負責維護Swarm編排,它管理集羣環境。
工做節點(Worker Node): 該節點負責執行管理節點定義的任務。 它將始終將其狀態通知給Manager節點並提供分配給它的服務。
任務(Task): 任務包含一個Docker容器和在容器內運行的命令,它是swarm的原子調度單元,若是某一個任務奔潰,那麼協調器將建立一個新的副本任務,該任務將生成一個新的容器
Docker Swarm和k8s都是目前的容器編排的主流技術,可是目前市場上大多數企業都是用k8s進行容器集羣管理,k8s的背靠Google這棵大樹,開源社區也很是活躍,隨着這些年雲廠商的迅速發展,k8s是將來趨勢,我我的建議在真實項目仍是使用k8s進行容器編排和管理,不過這裏是docker專場,我暫很少說,會在後面k8s專題去講這一塊內容。
假如沒有Swarm這類多機容器管理技術,咱們很難對容器進行管理,而且容器之間沒辦法實現跨機器通訊。而Docker swarm可讓用戶輕鬆在多個機器上發佈和管理應用,而且咱們不須要關注每一個容器實例具體落在哪個節點,swarm把咱們的應用以服務的形式暴露出去,並內置服務發現和負載均衡,讓運行在多個節點上的容器集羣感受就像只有一個應用在跑同樣簡單,能夠輕鬆實現擴容和自動容錯(一個swarm任務的容器奔潰會自動擴展一個新的容器
)。Swarm集羣一般有幾個工做程序節點和至少一個管理程序節點,負責高效地處理工做程序節點的資源並確保集羣有效地運行,提升了應用可用性。
如下三個網絡概念對於Swarm集羣服務很重要:
Overlay - Overlay
網絡管理參與集羣的Docker守護程序之間的通訊。您可使用與獨立容器的用戶定義網絡相同的方式建立Overlay
網絡。您也能夠將服務附加到一個或多個現有的Overlay
網絡,以啓用服務到服務的通訊。Overlay
網絡是使用Overlay
網絡驅動程序的Docker網絡。
ingress - ingress
網絡是一種特殊的Overlay
網絡,可促進服務節點之間的負載均衡。當任何集羣節點在已發佈的端口上收到請求時,會將請求轉交給名爲IPVS的模塊。 IPVS經過ingress
網絡跟蹤參與該服務的全部IP地址,選擇其中一個並將請求發送給它。
當對節點進行swarm init
或swarm join
時,會自動建立ingress
網絡。大多數用戶不須要自定義其配置,可是Docker 17.05及更高版本容許您自定義。
docker_gwbridge - docker_gwbridge
是一個橋接網絡,它將overlay
網絡(包括ingress
網絡)鏈接到單個Docker守護程序的物理網絡。默認狀況下,服務正在運行的每一個容器都鏈接到其本地Docker守護程序主機的docker_gwbridge
網絡。
初始化或加入集羣時會自動建立docker_gwbridge
網絡。大多數用戶不須要自定義其配置,可是Docker容許您自定義。
Docker Engine內有一個嵌入式DNS服務器,當Docker不以Swarm模式運行時,容器會使用這個服務器;而當Docker Engine以Swarm模式運行時,該服務器將用於任務。 它爲bridge
,Overlay
或MACVLAN
網絡中主機上的全部容器提供名稱解析。 每一個容器將其查詢請求轉發到Docker引擎,後者依次檢查該容器或服務是否與首先發送請求的容器在同一網絡上。 若是是,它將在其內部鍵值存儲中搜索與容器、任務或服務的名稱匹配的IP(或虛擬IP)地址,並將其返回給發送請求的容器。
若是匹配的資源與生成請求的容器在同一網絡內,則Docker引擎只會返回IP地址。 這樣作的好處還在於,Docker主機僅存儲屬於該節點在其中具備容器或任務的網絡的DNS條目。 這意味着它們將不會存儲實際上與他們無關的信息,或者其餘容器不須要知道的信息。
在上圖中,有一個名爲custom-net
的自定義網絡。 網絡上運行着兩種服務:myservice和myclient。 myservice有兩個與之關聯的任務,而客戶端只有一個。
客戶端myclient
而後執行對myservice的curl請求,所以,它也在對DNS進行請求。 容器內置的解析器將查詢轉發到Docker引擎的DNS服務器。 而後,對myservice的請求將解析爲10.0.0.2虛擬IP,轉發回客戶端,客戶端就能夠經過虛擬ip去訪問容器。
建立服務後,Docker將自動啓用此功能。 所以,建立服務後,它會當即在服務的網絡上得到虛擬IP地址。 就像上文在服務發現部分中所說的那樣,當請求服務時,所獲得的DNS查詢將轉發到Docker引擎,該引擎進而返回服務的IP,即虛擬IP。 發送到該虛擬IP的流量將負載均衡到網絡上該服務的全部正常運行的容器。 全部負載均衡均由Docker完成,由於只有一個入口點被分配給客戶端(一個IP)。
默認狀況下,不會激活負載均衡,當在建立或更新時使用–publish
標誌公開服務時,集羣中的每一個節點都會開始偵聽已發佈的端口,這意味着每一個節點均可以響應對映射到該端口的服務的請求。
當某個節點接收到一個請求,但該節點沒有容器實例時,會發生什麼? 從Docker 1.12(將Swarm模式集成到Docker Engine的同一版本)開始,就有一個名爲Routing Mesh
的功能,該功能使用IP虛擬服務器(ipvs)和iptables來負載均衡第4層中的請求。基本上,ipvs實現了第4層 Linux內核上的負載均衡功能,該功能容許將對基於TCP / UDP
的服務的請求重定向到實際的後端(在這種狀況下爲容器)。 在Swarm的特定狀況下,每一個節點都偵聽暴露的端口,而後使用稱爲ingress
的特殊Overlay
網絡將請求轉發到暴露的服務的VIP(虛擬IP)。 僅當將外部流量傳輸到請求的服務時,才使用此Overlay
網絡。 在這種狀況,docker會使用與上文描述的相同的內部負載均衡策略。
在上圖中,在appnet Overlay
網絡上建立了具備兩個副本的服務。 咱們能夠看到該服務在三個節點上的8000
端口上公開,此時,發往應用程序的流量能夠轉發到任何節點。 假設在這種狀況下,有一個外部負載均衡器,它剛好將請求轉發到惟一沒有該服務實例的節點, 該請求由IPVS在第三個節點上處理和轉發,該IPVS使用ingress
網絡並所以使用上述負載均衡方法將其重定向到該服務的集羣上的其中一個真實運行的容器。
上圖來自官方,很清晰展現了在swarm模式,manage節點和worker節點是怎麼協做的,這裏就不作細說了。
credit-facility-net
credit-facility-volume
,用於持久化Mysql容器數據由於我機器資源不夠,我這裏只是建立了三臺虛擬機,manager節點也是能夠部署服務的
這裏用到Vagrant來管理虛擬機,若是不知道Vagrant是什麼,請查看第一章內容。Vagrant指令能夠查看Vagrant詳細指令文檔
1.在咱們的主機(你本身的電腦)建立一個文件夾swarm-centos7
,而後在目錄下建立一個Vagrantfile
文件
Vagrant
boxes = [ { :name => "manager-node", :eth1 => "192.168.101.11", :mem => "1024", :cpu => "1" }, { :name => "worker01-node", :eth1 => "192.168.101.12", :mem => "1024", :cpu => "1" }, { :name => "worker02-node", :eth1 => "192.168.101.13", :mem => "1024", :cpu => "1" } ] Vagrant.configure(2) do |config| config.vm.box = "centos7" boxes.each do |opts| config.vm.define opts[:name] do |config| config.vm.hostname = opts[:name] config.vm.provider "vmware_fusion" do |v| v.vmx["memsize"] = opts[:mem] v.vmx["numvcpus"] = opts[:cpu] end config.vm.provider "virtualbox" do |v| v.customize ["modifyvm", :id, "--memory", opts[:mem]] v.customize ["modifyvm", :id, "--cpus", opts[:cpu]] v.customize ["modifyvm", :id, "--name", opts[:name]] end config.vm.network :public_network, ip: opts[:eth1] end end end
這裏指定了三臺虛擬機的配置,而且分別分配了一個靜態ip 192.168.101.11
、192.168.101.12
和192.168.101.13
,而且循環建立虛擬機。這裏指定了docker swarm
最低要求配置1個CPU、1G內存。
2.啓動三臺虛擬機,記得在啓動過程選擇你可用的網卡
evans-MacBook-Pro:swarm-centos7 evan$ vagrant up
當該命令執行完畢,會有三臺虛擬機成功被初始化
由於後面須要用到ssh客戶端工具,因此這裏要把密碼開放下
修改 manager 節點訪問密碼,用於後面上傳文件使用,這裏的密碼是evan123
[root@manager-node local]# passwd Changing password for user root. New password: BAD PASSWORD: The password fails the dictionary check - it is too simplistic/systematic Retype new password: passwd: all authentication tokens updated successfully.
這裏只演示了manager節點,另外兩個worker節點也須要作一樣的操做
須要在每一個節點安裝Docker,請使用SSH客戶端工具,分別登錄3個虛擬機,先按如下步驟安裝docker
1.卸載以前的docker配置,若有
sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine
2.安裝服務器必要的依賴
sudo yum install -y yum-utils \ device-mapper-persistent-data \ lvm2
3.配置加速器,由於國內下載docker須要越過長城,會比較慢,這裏我用到的是我本身的阿里雲加速器,若是不知道怎麼配置的,請查看第一章
sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://6xh8u88j.mirror.aliyuncs.com"] } EOF sudo systemctl daemon-reload sudo systemctl restart docker
4.設置Docker倉庫
sudo yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo
5.安裝Docker
sudo yum install -y docker-ce docker-ce-cli containerd.io
6.安裝完畢後,分別進入manger節點和2個worker節點,啓動docker服務
[root@manager-node ~]# systemctl start docker
7.驗證docker,輸入docker info
,驗證下docker是否已經安裝成功
這裏須要先進入manager節點192.168.101.11
進行swarm初始化操做,
[root@manager-node credit-facility]# docker swarm init --advertise-addr=192.168.101.11 Swarm initialized: current node (tdtu8tl63zqim8jrbzf8l5bcn) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-61e18f81408f4ja2yrcn9l11y5x21okcx58d3f6gcptyydb0iz-9hquv710qpx8s4h88oy2fycei 192.168.101.11:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
這裏會生成一串token,隨後須要在worker節點使用該命令去加入到swarm集羣中
這裏咱們須要分別進去兩個worker節點192.168.101.12
和 192.168.101.13
執行如下操做
docker swarm join --token SWMTKN-1-61e18f81408f4ja2yrcn9l11y5x21okcx58d3f6gcptyydb0iz-9hquv710qpx8s4h88oy2fycei 192.168.101.11:2377
這裏表示當前節點加入swarm集羣
只能在swarm manager節點查看當前全部節點信息
[root@manager-node credit-facility]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION tdtu8tl63zqim8jrbzf8l5bcn * manager-node Ready Active Leader 19.03.7 n8m358c7ta18206gzey7xsvw8 worker01-node Ready Active 19.03.7 pgzph6ye6xl1p9fz0hif191kn worker02-node Ready Active 19.03.7
這裏能夠看到,咱們的3個節點都已經成功加入到swarm集羣,manager-node是咱們的swarm集羣 leader
跟前一章同樣,在集羣三個節點的/usr/local
下,分別建一個credit-facitliy
目錄
[root@worker01-node local]# mkdir credit-facility
# for docker-stack demo spring.datasource.url = jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_NAME}?useUnicode=true&characterEncoding=utf8 #spring.datasource.url = jdbc:mysql://192.168.101.23:3301/db_credit_facility?useUnicode=true&characterEncoding=utf8 #配置數據庫用戶名 #spring.datasource.username = root spring.datasource.username = ${DB_USER} #配置數據庫密碼 #spring.datasource.password = evan123 spring.datasource.password = ${DB_PASSWORD}
配置文件我已經在項目裏提早修改好了,你們直接用便可
mvn clean package
,打包後在star目錄下evans-MacBook-Pro:target evan$ sftp root@192.168.101.11 root@192.168.101.11's password: Connected to root@192.168.101.11. sftp> put start-1.0.0-SNAPSHOT.jar /usr/local/credit-facility Uploading start-1.0.0-SNAPSHOT.jar to /usr/local/credit-facility/start-1.0.0-SNAPSHOT.jar start-1.0.0-SNAPSHOT.jar 100% 43MB 76.5MB/s 00:00 sftp>
evans-MacBook-Pro:target evan$ sftp root@192.168.101.12 root@192.168.101.11's password: Connected to root@192.168.101.12. sftp> put start-1.0.0-SNAPSHOT.jar /usr/local/credit-facility Uploading start-1.0.0-SNAPSHOT.jar to /usr/local/credit-facility/start-1.0.0-SNAPSHOT.jar start-1.0.0-SNAPSHOT.jar 100% 43MB 76.5MB/s 00:00 sftp>
evans-MacBook-Pro:target evan$ sftp root@192.168.101.13 root@192.168.101.11's password: Connected to root@192.168.101.13. sftp> put start-1.0.0-SNAPSHOT.jar /usr/local/credit-facility Uploading start-1.0.0-SNAPSHOT.jar to /usr/local/credit-facility/start-1.0.0-SNAPSHOT.jar start-1.0.0-SNAPSHOT.jar 100% 43MB 76.5MB/s 00:00 sftp>
/usr/local/credit-facility
目錄下,建立Dockerfile[root@manager-node credit-facility]# cat Dockerfile FROM openjdk:8-jre-alpine MAINTAINER evan LABEL name="credit-facility" version="1.0" author="evan" COPY start-1.0.0-SNAPSHOT.jar credit-facility-service.jar CMD ["java","-jar","credit-facility-service.jar"]
該文件我已經提早放置在額度服務項目裏,直接copy便可
/usr/local/credit-facility
目錄下,執行如下命令建立額度服務鏡像,這裏只演示manager
節點,其餘節點操做同樣[root@manager-node credit-facility]# docker build -t credit-facility-image . Sending build context to Docker daemon 44.92MB Step 1/5 : FROM openjdk:8-jre-alpine ---> f7a292bbb70c Step 2/5 : MAINTAINER evan ---> Running in 50b0ae0125ef Removing intermediate container 50b0ae0125ef ---> b4231d681d22 Step 3/5 : LABEL name="credit-facility" version="1.0" author="evan" ---> Running in 4a6bb0ae9f12 Removing intermediate container 4a6bb0ae9f12 ---> ea441d121fc4 Step 4/5 : COPY start-1.0.0-SNAPSHOT.jar credit-facility-service.jar ---> 0bed9d9397f6 Step 5/5 : CMD ["java","-jar","credit-facility-service.jar"] ---> Running in 6bb0c14f1a85 Removing intermediate container 6bb0c14f1a85 ---> de2606eea641 Successfully built de2606eea641 Successfully tagged credit-facility-image:latest
建立完查看下每一個節點現有的鏡像列表:
[root@worker01-node credit-facility]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE credit-facility-image latest 8dcef5954aaa 3 hours ago 130MB openjdk 8-jre-alpine f7a292bbb70c 10 months ago 84.9MB
從上面查詢結果能夠看到,咱們的額度服務鏡像已經成功建立
由於咱們後面用到Nginx
服務,因此咱們須要提早把配置建立後,而後經過--mount
方式把配置文件覆蓋Nginx
容器內的默認配置
在/usr/local/credit-facility
文件夾下,建立一個nginx
目錄,並在nginx
目錄下建一個nginx.conf
配置文件
[root@manager-node nginx]# cat nginx.conf user nginx; worker_processes 1; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; location / { proxy_pass http://balance; } } upstream balance{ server credit-facility-service:8080; } include /etc/nginx/conf.d/*.conf; }
我這裏利用docker swam
內置DNS原理,我這裏配置域名是額度服務名稱credit-facility-service
,docker swarm
會自動幫咱們路由到對應的服務節點上
/usr/local/credit-facility
文件夾下,建立一個docker-stack.yml
用於建立和管理服務(注意,這裏只須要manager節點建立便可,manager節點會把docker service
發佈到到其餘節點)[root@manager-node credit-facility]# cat docker-stack.yml version: '3' services: db: restart: always image: mysql build: context: /usr/local/credit-facility ports: - 3306:3306/tcp volumes: - "credit-facility-volume:/var/lib/mysql:rw" environment: - MYSQL_DATABASE=db_credit_facility - MYSQL_ROOT_PASSWORD=evan123 networks: - demo-overlay deploy: mode: global placement: constraints: - node.role == manager credit-facility-service: restart: always image: credit-facility-image build: context: /usr/local/credit-facility ports: - 8080:8080 environment: - DB_HOST=db - DB_PORT=3306 - DB_USER=root - DB_PASSWORD=evan123 - DB_NAME=db_credit_facility networks: - demo-overlay deploy: mode: replicated replicas: 3 restart_policy: condition: on-failure delay: 5s max_attempts: 3 update_config: parallelism: 1 delay: 10s nginx: restart: always depends_on: - db - credit-facility-service image: nginx ports: - "80:80" volumes: - /usr/local/credit-facility/nginx/nginx.conf:/etc/nginx/nginx.conf networks: - demo-overlay deploy: mode: global placement: constraints: - node.role == manager networks: demo-overlay: driver: overlay volumes: credit-facility-volume: {}
docker stack
去發佈服務,能夠將服務發佈到集羣各個節點上(docker compose
是用於單機部署,多機部署須要用到docker swarm stack
)[root@manager-node credit-facility]# docker stack deploy -c docker-stack.yml web Ignoring unsupported options: build, restart Ignoring deprecated options: container_name: Setting the container name is not supported. Creating network web_credit-facility-net Creating service web_nginx Creating service web_db Creating service web_credit-facility-service ...
[root@manager-node nginx]# docker service ls ID NAME MODE REPLICAS IMAGE PORTS 3qcjnj7n5dkk web_credit-facility-service replicated 3/3 credit-facility-image:latest *:8080->8080/tcp t5omqvum57ag web_db global 1/1 mysql:latest *:3306->3306/tcp w89fkne6fzcg web_nginx global 1/1 nginx:latest *:80->80/tcp
從上面結果能夠看到,咱們發佈的各個服務已經成功啓動,額度服務的3個實例也成功發佈到3個節點中
[root@manager-node nginx]# docker service ps web_credit-facility-service ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS pc32kfmfxke0 web_credit-facility-service.1 credit-facility-image:latest worker01-node Running Running 23 minutes ago 8v9efe61p5wb web_credit-facility-service.2 credit-facility-image:latest manager-node Running Running 23 minutes ago sg1wh95lxyca web_credit-facility-service.3 credit-facility-image:latest worker02-node Running Running 23 minutes ago
上面結果能夠清晰看到,每個實例被髮布到哪一個節點中
跟前面章節同樣,由於額度服務對數據庫有依賴,因此這裏須要初始化額度服務用到的表,使用Mysql客戶端,鏈接到數據庫,把項目裏resources/db
的表建立語句放入執行,我這裏用Navicat去鏈接,數據庫鏈接是192.168.101.11:3306
到這裏,全部的配置已經完成了,咱們來一塊兒覈對下現有的文件有哪些,看看你們有沒有遺漏的惡配置
在manager節點的credit-facility
文件夾下,應該有如下文件
[root@manager-node credit-facility]# ls docker-compose.yaml Dockerfile docker-stack.yml nginx start-1.0.0-SNAPSHOT.jar
在2個worker節點的credit-facility
文件夾下,應該有如下文件
worker-01節點
[root@worker01-node credit-facility]# ls Dockerfile start-1.0.0-SNAPSHOT.jar
worker-02節點
[root@worker02-node credit-facility]# ls Dockerfile start-1.0.0-SNAPSHOT.jar
192.168.101.11http://192.168.101.11/swagger-ui.html
能夠訪問到咱們的額度服務ip+8080
訪問咱們的服務由於咱們額度服務有用到數據庫,這裏咱們實驗下調用額度服務的接口,看是否能夠成功入庫
請求參數以下:
{ "registrationLimitCO": { "applicationId": "1111", "userId": 1111, "quotaLimit": 10000, "productCode": "tb", "expirationTime": "2030-01-01", "accountType": 1 } }
執行額度註冊接口
執行結果:
從上面執行結果能夠看到,咱們的接口已經成功處理咱們的請求,而且入庫成功,有興趣的同窗能夠到數據庫去查看相應記錄
[root@manager-node credit-facility]# docker stack ls NAME SERVICES ORCHESTRATOR web 3 Swarm
docker-stack.yml
建立服務docker statck deploy -c docker-stack.yml web
[root@manager-node credit-facility]# docker service inspect web_db ... "Endpoint": { "Spec": { "Mode": "vip", "Ports": [ { "Protocol": "tcp", "TargetPort": 3306, "PublishedPort": 3306, "PublishMode": "ingress" } ] }, "Ports": [ { "Protocol": "tcp", "TargetPort": 3306, "PublishedPort": 3306, "PublishMode": "ingress" } ], "VirtualIPs": [ { "NetworkID": "5mmql4cfhoac6q3y67wm4x2uh", "Addr": "10.0.0.122/24" }, { "NetworkID": "xx3b6lki8n1nvkphffretc050", "Addr": "10.0.6.12/24" } ] } ...
docker service create --name my-nginx nginx
docker service ls
docker service logs my-nginx
ocker service inspect my-nginx
docker service ps my-nginx
docker service scale my-nginx=3 docker service ls docker service ps my-nginx
docker service rm my-nginx