接上一篇:面試官:你說你精通 Docker,那你來詳細說說 Dockerfile 吧
一、容器之間通信
1、單向通信
1.1、什么意思

mysql和tomcat是兩個獨立的容器,但是tomcat需要和mysql通信,而mysql完全不用和tomcat通信,這就叫容器之間的單向通信,
1.2、怎么通信
要談通信,就需要談一下ip,因為不知道ip是無法通信的,最簡單的例子你jdbc要連接mysql資料庫,你也需要配置mysql的ip地址,容器之間也不例外,都是靠虛擬ip來完成的,
何為虛擬ip?
虛擬ip:容器創建完成后都會生成一個唯一的ip,這個ip外界不能直接訪問,他只用于容器之間進行通信互動用,這就是虛擬ip,
容器之間的虛擬ip是互通的,
通信是什么意思、靠什么通信我們都知道了,那還不抓緊實戰一把?
1.3、實戰演示
1.3.1、創建tomcat容器
docker run -d --name mytomcat tomcat
# --name指定的名稱再docker ps里是可以看到的,最后一列Name
docker ps
知識點出現了!!!--name是神馬鬼?先看如下一個場景
在公司或者你直接買的阿里云資料庫/redis等服務為什么給你個資料庫域名而不是推薦用ip?因為ip的話可變,比如你業務系統寫死了ip,這時候人家那邊內網ip變了,你這所有用這個資料庫的業務系統都要跟著改,用域名的話一勞永逸,底層ip變了后再映射到新域名上就行,不影響業務系統,
--name就是給docker配置名稱來與虛擬ip做映射,因為ip老變化,每次變化的時候其他容器都需要跟著改動才行,配個名稱一勞永逸,創建容器的時候通過 --name xxx 即可指定,
1.3.2、創建mysql容器
我也沒拉取mysql鏡像,就用centos模擬一下資料庫吧,主要是看能不能ping 通,能ping 通就代表能通信,
docker run -d --name database -it centos /bin/bash
1.3.3、小試一把
我們需要進入mytomcat的容器然后去ping database的ip看看是否通,那么容器的虛擬ip怎么查呢?
# 這又是一個知識點
docker inspect 容器id
# 比如:(9bf58b4014dd是我們database的容器id)
docker inspect 9bf58b4014dd

現在知道資料庫的ip了,那趕緊進入我們的mytomcat的容器去ping一波
docker exec -it mytomcat /bin/bash
ping 172.17.0.6

完美!
等等,貌似不是很完美,我們給資料庫指定了名稱database,那我們趕緊ping database 試一下,結果啪啪啪打臉,完全不通,那是因為相當于你就起了個名字,并沒有做映射,那怎么映射呢?mytomcat啟動容器的時候指定一個--link引數即可,
# 強制洗掉老的
docker rm -f mytomcat
# 創建新的容器,用--link指定我們想連的配置的資料庫“域名”
docker run -d --name mytomcat --link database tomcat
# 進入mytomcat容器
docker exec -it mytomcat /bin/bash
# ping
ping database

這次是真的完美~!
1.4、總結
-
容器簡單虛擬ip是互通的
-
用--name 和 --link可以完成自定義“域名”來取代可變化的ip
2、雙向通信
方式有很多,一般都采取橋接方式,由于篇幅過長,自行Google即可,重點搞懂了容器間的通信是什么意思,大概怎么做即可,比如上面的--link也是其一做法,
二、容器間資料共享
1、場景
需要宿主機和容器之間共享資料的業務場景,比如Mysql的
比如:集群部署的時候,我們的應用程式需要部署到10個docker容器里,那么比如要想改動一個檔案的內容,就要重新打包然后部署10次,我們可以將我們需要部署的應用程式掛載到宿主機上,這樣改一處就行了,比如靜態html檔案,再一個宿主機上啟動了10個容器,這時候需求需要改文案(修改html),我們需要修改10個容器里的html,過于麻煩,所以可以把這個html掛載到宿主機,容器直接使用掛載到宿主機的檔案即可,
再比如:Mysql的資料目錄可組態檔(一些高級配置或者優化配置啥的肯定要用一份),這也可以用此場景,
2、語法
# 語法
docker run -v 宿主機路徑:容器內掛載路徑 鏡像名
# 比如如下:他會把/home/main/programe下面的所有目錄都掛載到容器的/usr/local/tomcat/webapps下
docker run -v /home/main/programe:/usr/local/tomcat/webapps tomcat
3、實戰
3.1、準備
在如下目錄里創建如下檔案,并寫上Hello Volumn~
/home/main/docker/webapps/volumn-test/index.html
3.2、操作
很簡單,按照上面的語法來就成了,如下就是將/home/main/docker/webapps下的目錄掛載到容器內部/usr/local/tomcat/webapps的目錄下
docker run --name t2 -d -p 8200:8080 -v /home/main/docker/webapps:/usr/local/tomcat/webapps tomcat
3.3、驗證
我們先進入容器
docker exec -it t2 /bin/bash
然后查看/usr/local/tomcat/webapps下是否有我們掛載的目錄以及檔案
root@4be396ff443b:/usr/local/tomcat/webapps# ls -R volumn-test/
volumn-test/:
index.html
最后我們訪問下看看效果
[root@izm5 volumn-test]# curl 'localhost:8200/volumn-test/index.html'
Hello Volumn~~
我們修改下宿主機上的index.html的內容,修改為Hello Volumn~~ How are you?然后再次訪問看效果:
這里修改的是宿主機
/home/main/docker/webapps/volumn-test下的index.html,為不是容器內部的,
[root@izm5 volumn-test]# curl 'localhost:8200/volumn-test/index.html'
Hello Volumn~~ How are you?
很完美,容器無感知的就生效了,
3.4、好處
我這是啟動了一個容器舉例,如果多啟動幾個呢?然后產品要修改文案,那么你登錄每個容器里去修改?或者重新打包然后重新啟動所有容器?有點小題大做呀,利用-v命令進行掛載實作宿主機和容器的資料共享她不香嗎?
4、新的問題
如果容器過多,那么每次啟動容器都要-v xxx:xxx,這也很容易寫錯啊,寫錯一個字母都不行,還有,如果宿主機換地址了,這也需要批量更換容器的docker run -v的引數,機器太多不利于維護,
5、解決問題
共享容器誕生了!
5.1、共享容器概念
如果容器太多,每一次都要寫-v xxx:xxx,過于復雜,也容易出錯,這時候可以通過docker create創建共享容器,然后啟動的時候通過--volumes-from指定創建的共享容器名稱即可,也就是說可以把上面-v xxx:xxx這一串統一放到一個地方去管理,容器啟動的時候直接參考這個統一配置即可,方便統一管理,
5.2、語法
# 創建共享容器語法,只是創建不是啟動,最后的/bin/true 就是一個占位符,沒啥亂用,
docker create --name 共享容器名稱 -v 宿主機路徑:容器內掛載路徑 鏡像名稱 /bin/true
# 啟動容器的時候通過--volumes-from 共享容器名稱來使用共享容器掛載點
docker run --volumes-from 共享容器名稱 --name xxx -d 鏡像名稱
5.3、實戰
# 創建共享容器 docker create --name webpage -v /home/main/docker/webapps:/usr/local/tomcat/webapps tomcat /bin/true # 采取共享容器的配置來啟動容器 docker run -p 8300:8080 --volumes-from webpage --name t3 -d tomcat # 在啟動個 docker run -p 8400:8080 --volumes-from webpage --name t4 -d tomcat
5.4、驗證&&好處
驗證跟第一種-v的方式一樣,修改內容,容器無感知,
相對于第一種方式的好處是:
-
不用每次都寫
-v xxx:xxx這一長串不僅令人厭惡還容易出現錯誤的英文字母, -
更改路徑,只修改一處即可,
三、DockerCompose
1、有什么用
比如我們要部署一個javaweb應用,那一般情況都需要三個容器:nginx容器、tomcat容器、mysql容器,這是最基本的,可能更復雜,那運維人員每次都需要單獨啟動這三個容器來支撐我們的web應用嗎?有點復雜了,
docker-compose就是為了簡化這個程序的,相當于是個腳本,把這三個容器用腳本統一來管理和啟動,節省運維時間和避免出錯率,也就是說多應用互相協同才能完成一件事的時候,是很好用的,否則直接Dockerfile就完了,
2、安裝DockerCompose
基于Linux的安裝,
參考的官方安裝檔案:https://docs.docker.com/compose/install/
執行如下兩個命令就完事了:
sudo curl -L "https://github.com/docker/compose/releases/download/1.25.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
如果第一個命令特別慢的話可以用如下命令代替,畢竟是國外網站
> curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.5/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
安裝完進行驗證:
docker-compose --version
3、實戰感受一下
先來感受一下docker-compose的威力,部署下WordPress來玩玩,不知道WordPress是啥的自己百度,就是一個開源博客,
為什么是部署WordPress,因為官方也是WordPress….面向官方檔案學習…
官方檔案安裝WordPress的教程:https://docs.docker.com/compose/wordpress/
(1)建立如下目錄
/home/main/docker/WordPress
(2)建立docker-compose.yml檔案
cd /home/main/docker/WordPress
vi docker-compose.yml
(3)在docker-compose.yml里寫上如下內容
version: '3.3' services: db: image: mysql:5.7 volumes: - db_data:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: somewordpress MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress wordpress: depends_on: - db image: wordpress:latest ports: - "8000:80" restart: always environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress WORDPRESS_DB_NAME: wordpress volumes: db_data: {}
看不懂?正常,也沒關系,這就是大名鼎鼎的docker-compose,就是一個一.yml為后綴結尾的腳本檔案,他能自動幫我們部署我們配置的容器,比如上述有mysql容器和wordpress容器,我們還能看到埠是8000,這就夠了,開干!
(4)執行腳本
# 先進入你的docker-compose.yml所在的目錄
cd /home/main/docker/WordPress
# 執行腳本
docker-compose up -d
(5)結果分析
[root@izm5e3qug7oee4q1y4opibz WordPress]# docker-compose up -d Creating network "wordpress_default" with the default driver Creating volume "wordpress_db_data" with default driver Pulling db (mysql:5.7)... 5.7: Pulling from library/mysql afb6ec6fdc1c: Pull complete .... 0bdc5971ba40: Pull complete Digest: sha256:d16d9ef7a4ecb29efcd1ba46d5a82bda3c28bd18c0f1e3b86ba54816211e1ac4 Status: Downloaded newer image for mysql:5.7 Pulling wordpress (wordpress:latest)... latest: Pulling from library/wordpress afb6ec6fdc1c: Already exists 3d895574014b: Pull complete ... Digest: sha256:0b452b7b45fa770f12e864720abb01bef506f4abe273669402434e94323c97d7 Status: Downloaded newer image for wordpress:latest Creating wordpress_db_1 ... done Creating wordpress_wordpress_1 ... done
可以看到pulling db、pulling wordpress、done,大概了解到為我們創建了wordpress和wordpress所需要的mysql資料庫,訪問8000埠,大功告成!

4、和Dockerfile區別
Dockerfile容器間通信需要--link或者橋接方式進行,而DockerCompose全自動的呀,也就是說單容器的話肯定Dockerfile了,但是多容器之間需要互動、有依賴關系,那用DockerCompose來統一管理那些零散的Dockerfile來達到自動構建部署的一體化腳本,
5、實戰
5.1、需求描述
實戰一個spring boot的專案,一個springboot的jar包依賴mysql資料庫,我們用docker-compose完成自動化部署,
5.2、準備作業
5.2.1、 準備如下檔案
[root@izm5e3qug7oee4q1y4opibz docker-compose-app]# pwd /home/main/docker/docker-compose-app [root@izm5e3qug7oee4q1y4opibz docker-compose-app]# ls -l total 12 drwxr-xr-x 2 root root 4096 May 24 12:20 app drwxr-xr-x 2 root root 4096 May 24 12:20 db -rw-r--r-- 1 root root 335 May 24 12:20 docker-compose.yml
5.2.2、app
里面就是我們的springboot的jar包和制作鏡像的Dockerfile檔案,
[root@izm5e3qug7oee4q1y4opibz docker-compose-app]# ll app/ total 23492 -rw-r--r-- 1 root root 1071 May 24 12:19 application-dev.yml -rw-r--r-- 1 root root 1457 May 24 12:19 application.yml -rw-r--r-- 1 root root 24042957 May 24 12:20 bsbdj.jar -rw-r--r-- 1 root root 154 May 24 12:20 Dockerfile
看下application-dev.yml的配置,主要看資料庫配置:
spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://db:3306/bsbdj?useUnicode=true username: root password: root tomcat: init-s-q-l: SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci server: port: 80
這里我們發現貓膩了,資料庫配置是db:3306,這不是平常的ip/域名神馬的,這個是Mysql容器名稱,所以這個服務依賴mysql服務,所以我們的主要目的就是利用DockerCompose來自動化操作多容器的Dockerfile檔案來自動部署和初始化SQL的操作,
5.2.3、db
jar包所需要的資料庫的sql檔案和制作鏡像的Dockerfile檔案,
[root@izm5e3qug7oee4q1y4opibz docker-compose-app]# ll db/ total 35612 -rw-r--r-- 1 root root 69 May 24 12:20 Dockerfile -rw-r--r-- 1 root root 36460577 May 24 12:20 init-db.sql
5.3、開始實戰
5.3.1、app的Dockerfile
FROM openjdk:8u222-jre WORKDIR /usr/local/bsbdj ADD bsbdj.jar . ADD application.yml . ADD application-dev.yml . EXPOSE 80 CMD ["java","-jar","bsbdj.jar"]
5.3.2、db的Dockerfile
FROM mysql:5.7 WORKDIR /docker-entrypoint-initdb.d ADD init-db.sql .
這里有個細節:為什么是進入docker-entrypoint-initdb.d這目錄在ADD sql?因為這個目錄是個后門,這個目錄下的sql檔案會自動執行,我咋知道的?官方告訴我的:
https://hub.docker.com/_/mysql

5.3.3、最終Boss:docker-compose.yml
現在我們應用程式的Dockerfile和應用程式所依賴的資料庫Dockerfile都已就緒,還剩下最后一個終極yml組態檔
# 目前最穩定版本:3.3,所以3.3就行, version: '3.3' services: ## 服務名稱叫 db,還記得我們application-dev.yml的配置嗎?資料庫配置的是db,對應的就是這里了, db: # Dockerfile檔案所屬的目錄, build: ./db/ # always:宕機自動重啟,牛逼的很, restart: always # 環境變數,類似于-e引數 environment: MYSQL_ROOT_PASSWORD: root # 服務名稱叫 app app: # Dockerfile檔案所屬的目錄,若app依賴db,則需要把db服務配置放到app的前面, build: ./app/ # 依賴上面的db service depends_on: - db # 宿主機和容器的埠均為80,上面app的Dockerfile暴露的是80埠,所以這里容器是80 ports: - "80:80" restart: always
5.3.4、啟動
# -d代表后臺啟動
docker-compose up -d
啟動結果:
[root@izm5e3qug7oee4q1y4opibz docker-compose-app]# docker-compose up -d Creating network "docker-compose-app_default" with the default driver Building db Step 1/3 : FROM mysql:5.7 ---> a4fdfd462add Step 2/3 : WORKDIR /docker-entrypoint-initdb.d ---> Running in d1ff6e4bb5a8 Removing intermediate container d1ff6e4bb5a8 ---> d29a05c5bfcb Step 3/3 : ADD init-db.sql . ---> 6ae6d9eb35ca Successfully built 6ae6d9eb35ca Successfully tagged docker-compose-app_db:latest WARNING: Image for service db was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`. Building app Step 1/7 : FROM openjdk:8u222-jre 8u222-jre: Pulling from library/openjdk 9a0b0ce99936: Pull complete db3b6004c61a: Pull complete f8f075920295: Pull complete 4901756f2337: Pull complete 9cfcf0e1f584: Pull complete d6307286bdcd: Pull complete Digest: sha256:3d3df6a0e485f9c38236eaa795fc4d2e8b8d0f9305051c1e4f7fbca71129b06a Status: Downloaded newer image for openjdk:8u222-jre ---> 25073ded58d2 Step 2/7 : WORKDIR /usr/local/bsbdj ---> Running in df4a4c352e71 Removing intermediate container df4a4c352e71 ---> 0d88b2f13319 Step 3/7 : ADD bsbdj.jar . ---> aabaa119855d Step 4/7 : ADD application.yml . ---> 7e1f7b4614cc Step 5/7 : ADD application-dev.yml . ---> a8d36115592f Step 6/7 : EXPOSE 80 ---> Running in 26b44c9d57ef Removing intermediate container 26b44c9d57ef ---> fd36f3cdd115 Step 7/7 : CMD ["java","-jar","bsbdj.jar"] ---> Running in 64bdeff2f1ce Removing intermediate container 64bdeff2f1ce ---> 77d18bae9bbc Successfully built 77d18bae9bbc Successfully tagged docker-compose-app_app:latest Creating docker-compose-app_db_1 ... done Creating docker-compose-app_app_1 ... done
可以看到先為我們構建了mysql的鏡像然后又構建了bsbdj.jar的鏡像,最后執行了
CMD ["java","-jar","bsbdj.jar"],這些程序全自動化,
查看容器
docker-compose ps
結果:
[root@izm5e3qug7oee4q1y4opibz docker-compose-app]# docker-compose ps Name Command State Ports ------------------------------------------------------------------------------------ docker-compose-app_app_1 java -jar bsbdj.jar Up 0.0.0.0:80->80/tcp docker-compose-app_db_1 docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp
然后訪問http://ip:80即可看到效果,
6、補充
docker-compose其他命令可以用docker-compose --help查看,再說下docker-compose和Dockerfile區別,可以粗糙理解成Dockerfile是針對單容器的腳本,docker-compose是針對多Dockerfile的自動化腳本,他幫我們處理容器之間的依賴關系和其他需要人為干涉的操作,
四、上期答疑
上期回顧:面試官:你說你精通 Docker,那你來詳細說說 Dockerfile 吧
1.ADD命令能否解壓zip格式?多模塊該怎么創建鏡像?
ADD命令不能解壓zip,親測,能解壓:tar, gzip, bzip2, etc,
多模塊恰巧是今天的主角docker-compose,可以為每一個模塊都書寫一個Dockerfile,然后用docker-compose去管理這些帶有依賴關系的模塊,
如果是集群的話,首選k8s,docker warm什么的,畢竟docker-compose致命缺點僅限在單機上,
2.有了docker commit為啥還要Dockerfile?
docker commit都是黑箱操作,過一段時間后自己都不知道這個鏡像是怎么做出來的,都安裝了什么,但是使用Dockerfile構建的鏡像,我們能清楚的知道都有哪一層,每層是干嘛的,修改也方便,易于維護,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/179249.html
標籤:Java
上一篇:利用反射給物件按順序賦值
下一篇:多執行緒:(優先級、守護執行緒)
