安裝Docker的環境要求:html
使用以下命令查看內核版本java
uname -r
複製代碼
1. 卸載舊版本(若是安裝過舊版本的話)node
yum remove -y docker*
複製代碼
2. 安裝須要的軟件包, yum-util 提供yum-config-manager功能,另外兩個是devicemapper驅動依賴的linux
yum install -y yum-utils
複製代碼
3. 設置yum源,並更新 yum 的包索引nginx
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum makecache fast
複製代碼
4. 查看全部倉庫中全部docker版本,並選擇特定版本安裝git
yum list docker-ce --showduplicates | sort -r
複製代碼
5. 我這裏使用docker-ce-18.09.9版本,由於這個版本我我的用的比較多github
yum install docker-ce-18.09.9 docker-ce-cli-18.09.9 containerd.io -y
複製代碼
到了這一步,若是前面的步驟沒出錯那麼Docker應該已經安裝成功了。Docker內部寫死了一個遠程的鏡像庫,就相似於Maven的中央倉庫同樣,咱們拉取的鏡像默認都是從這個遠程鏡像庫拉取的,很慢。能夠到 /etc/docker/daemon.json
配置阿里雲的鏡像加速器:docker
{
"registry-mirrors": ["https://4ulabqzs.mirror.aliyuncs.com"]
}
複製代碼
啓動docker並設置開機啓動:shell
systemctl start docker
systemctl enable docker
複製代碼
使用docker --help
命令查看docker都有哪些命令json
咱們經過一個Nginx的例子,把Docker鏡像,容器相關的經常使用命令都跑一遍,邊使用邊解釋:
拉取Nginx的鏡像,Nginx有不少版本,第一次用確定不知道該拉取那些版本,能夠到遠程鏡像倉庫看一下:registry.hub.docker.com/ ;我這裏就使用nginx:1.15.2
這個版本,若是不指定版本的話,默認拉取的是latest版本
docker pull nginx:1.15.2
複製代碼
鏡像拉取完成後,已經存儲在宿主機的硬盤上面了,使用docker images | grep nginx
能夠看到剛纔拉取的鏡像,開始運行
docker run -d --name mynginx -p 80:80 nginx:1.15.2
複製代碼
啓動起來以後咱們使用docker ps
查看nginx已經在運行了而且容器名稱是 mynginx,映射到宿主機的端口是80,此時,在瀏覽器就能夠訪問到Nginx了(注意:要訪問宿主機暴露出來的端口),下面咱們能夠進入容器看看Nginx安裝在什麼地方
docker exec -it mynginx /bin/bash
whereis nginx
複製代碼
配置文件在/etc/nginx/conf.d
目錄下,靜態頁面在/etc/share/nginx/html
目錄下,由於容器是會隨時關閉的,一旦關閉,容器在運行過程當中產生的數據都會丟失,而且維護容器內部的配置文件至關麻煩,因此此時咱們須要對容器內的文件進行掛載,讓他存儲在宿主機上面,基於這個Nginx鏡像從新生成一個容器,進行掛載
docker run -d --name nginx -p 81:80 -v /docker/nginx/config:/etc/nginx/conf.d -v /docker/nginx/html:/etc/share/nginx/html nginx:1.15.2
複製代碼
此時再次訪問瀏覽器已是404了,由於咱們本身去掛載了html目錄,因此容器內的html目錄被覆蓋了,裏面沒有html文件了。進入容器裏面找到/etc/share/nginx/html
發現裏面是空的,不要慌,由於咱們已經掛載了目錄,此時只須要把html文件放到宿主機的/docker/nginx/conf/
和/docker/nginx/html
目錄下便可,找到以前啓動的mynginx容器,把他的配置文件複製到宿主機
docker cp mynginx:/etc/nginx/conf.d /docker/nginx/config
docker cp mynginx:/etc/share/nginx/html /docker/nginx/html
複製代碼
文件複製完以後重啓容器:docker restart nginx
,瀏覽器再次訪問便可訪問到;
上面的例子跑的很順利,可是咱們忽略了一個細節:爲何經過宿主機映射出來的端口能夠訪問到容器呢,這就涉及到了Docker的網絡模式:
ifconfig
能夠看到,多了一個docker0
虛擬網卡,默認網關即是docker的IP地址,在主機上建立一對虛擬網卡veth pair設備,Docker將veth pair設備的一端放在新建立的容器中,並命名爲eth0(容器的網卡),另外一端放在主機中,以vethxxx這樣相似的名字命名,並將這個網絡設備加入到docker0網橋中服務容器化須要依賴一個Dockerfile的打包文件,文件的編寫格式以下:
先來編寫一個最簡單的Dockerfile,在服務器上建立一個eureka文件夾,把jar包放進去,並編寫Dockerfile文件
# 依賴的基礎鏡像
FROM java:8
# 把打包好的服務放到容器的根目錄下並更名叫app.jar
ADD service-eureka-0.0.1-SNAPSHOT.jar app.jar
# 容器啓動後要執行的命令,與CMD不一樣的是,ENTRYPOINT的命令沒法被覆蓋
ENTRYPOINT ["java", "-jar", "/app.jar"]
# 聲明容器對外暴露的端口(能夠不寫)
EXPOSE 8761
複製代碼
[root@localhost eureka]# ll
總用量 49248
-rw-r--r--. 1 root root 118 5月 23 16:39 Dockerfile
-rw-r--r--. 1 root root 50424847 5月 23 16:33 service-eureka-0.0.1-SNAPSHOT.jar
複製代碼
執行命令 docker build -t eureka:release .
命令解釋:
build
基於Dockerfile構建鏡像;-t
給生成的鏡像打標籤(tag);.
Dockerfile所在的目錄(這裏是當前目錄);最終會生成一個eureka鏡像,而後進行docker run
運行容器就行了;
Dockerfile是用來構建鏡像的一個模板,可使用他來構建咱們本身的應用程序,這種方式能夠很方便的進行服務容器化部署,這種方式是手動在服務器上進行構建;
手動構建的方式大量的工做量在運維同窗,並且運維同窗還須要知道你的服務依賴的基礎鏡像和容器內的日誌目錄,這部分的工做開發比較熟,使用maven集成的docker打包插件能夠把容器化的過程放在開發這邊,運維只須要跑一整條命令便可
<plugins>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.4.13</version>
<configuration>
<!-- 構建的鏡像的名稱 -->
<imageName>dockermvc:peter</imageName>
<dockerDirectory>${project.basedir}</dockerDirectory>
<skipDockerBuild>false</skipDockerBuild>
<resources>
<resource>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
複製代碼
經過Git,將代碼推送到服務器上,執行命令
mvn clean package docker:build docker:run
複製代碼
在本身的公司內部搭建鏡像倉庫,存放公司本身的鏡像(相似於maven的私服),須要單獨弄一臺物理機進行存放,從鏡像庫裏面拉取registry鏡像docker pull registry
,啓動在5000端口:docker run ....
;而後須要在以前的主機的配置一個鏡像地址vim /etc/docker/daemon.json
,添加insecure-registries
,指向這臺鏡像倉庫的地址:
{
"registry-mirrors": ["https://4ulabqzs.mirror.aliyuncs.com"],
"insecure-registries":["192.168.254.100:5000"]
}
複製代碼
重啓docker
systemctl restart docker
複製代碼
如今我把本地的eureka鏡像傳到倉庫裏面:
# 後面的ip是倉庫的地址
docker tag eureka 192.168.254.100:5000/eureka:tml
# 推送到倉庫
docker push 192.168.254.100:5000/eureka
複製代碼
執行完上面的步驟以後,訪問鏡像倉庫看看裏面有沒有:192.168.254.100:5000/v2/_catalog
1. Docker Compose
在微服務架構中,咱們須要打包的服務不少,規模通常的狀況下得有30多個微服務,在線上可能還要根據實際狀況動態擴縮容,不可能一個一個的進行build,這時候咱們須要對微服務項目進行統一管理。
Docker Compose將所管理的容器分爲三層,分別是工程( project),服務(service)以及容器( container)。 Docker Compose運行目錄下的全部文件( docker-compose.yml、 extends文件或環境變量文件等)組成一個工程(默認爲 docker-compose.yml所在目錄的目錄名稱)。一個工程可包含多個服務,每一個服務中定義了容器運行的鏡像、參數和依賴,一個服務可包括多個容器實例。 同一個docker compose內部的容器之間能夠用服務名相互訪問,服務名就至關於hostname,能夠直接 ping 服務名,獲得的就是服務對應容器的ip,若是服務作了擴容,一個服務對應了多個容器,則 ping 服務名 會輪詢訪問服務對應的每臺容器ip ,docker底層用了LVS等技術幫咱們實現這個負載均衡。
sudo curl -L https://github.com/docker/compose/releases/download/1.17.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
複製代碼
[root@localhost app]# ll
總用量 3
drwxr-xr-x. 2 root root 65 5月 23 16:39 eureka
drwxr-xr-x. 2 root root 64 5月 23 17:22 order
drwxr-xr-x. 2 root root 63 5月 23 17:23 user
複製代碼
每一個服務裏面都對應有一個Dockerfile文件
[root@localhost app]# ll eureka/; ll order/; ll user/
總用量 49248
-rw-r--r--. 1 root root 118 5月 23 16:39 Dockerfile
-rw-r--r--. 1 root root 50424847 5月 23 16:33 service-eureka-0.0.1-SNAPSHOT.jar
總用量 43024
-rw-r--r--. 1 root root 117 5月 23 16:38 Dockerfile
-rw-r--r--. 1 root root 44050593 5月 23 17:22 service-order-0.0.1-SNAPSHOT.jar
總用量 43024
-rw-r--r--. 1 root root 116 5月 23 16:36 Dockerfile
-rw-r--r--. 1 root root 44050819 5月 23 17:22 service-user-0.0.1-SNAPSHOT.jar
複製代碼
docker-compose.yaml
文件,並進行容器編排:version: '3'
services:
eureka:
build: eureka
container_name: eureka
restart: always
ports:
- "8761:8761"
user:
build: user
container_name: user
restart: always
depends_on:
- eureka
ports:
- "9001:9001"
order:
build: order
container_name: order
restart: always
depends_on:
- user
ports:
- "9002:9002"
複製代碼
具體的語法能夠參考官網的例子,寫的很詳細docs.docker.com/compose/com… 執行docker-compose up -d
就能夠對容器進行批量管理,固然也能夠進行擴縮容,給指定的服務擴容,使用docker scale
;
docker compose功能不夠強大,基本也就在開發環境用用,確定不會用它去上生產環境的,它存在一些問題:
準備2臺物理機:
swarm1:
docker swarm init --advertise-addr 192.168.18.236 --listen-addr 192.168.18.236
複製代碼
返回信息: docker swarm join --token SWMTKN-1-1zm6dj1d4du21w937isecmmgsmzzyfa9rzgad55iuk2yhu4bmg-daeiy9n6k5yaa11a7eg3j4ltu 192.168.18.236:2377
把這個命令複製到swarm2執行:
[root@swarm2 ~]# docker swarm join --token SWMTKN-1-1zm6dj1d4du21w937isecmmgsmzzyfa9rzgad55iuk2yhu4bmg-daeiy9n6k5yaa11a7eg3j4ltu 192.168.18.236:2377
This node joined a swarm as a worker.
複製代碼
在swarm1中查看集羣信息:
[root@swarm1 system]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
ry4anpndmeboenys44yw0pu2t * swarm1 Ready Active Leader 18.09.9
zqyzsadxc28hcytik2rh6sda9 swarm2 Ready Active 18.09.9
複製代碼
如今集羣已經創建:swarm1是主節點,swarm2是從節點
docker service create -p 80:80 --name nginx --replicas 2 nginx:1.15.2
複製代碼
查看集羣中服務列表
[root@swarm1 system]# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
fx00qoitocdj nginx replicated 2/2 nginx:1.15.2 *:80->80/tcp
複製代碼
已經啓動了2個nginx副本,對外暴露的端口都是80
,在swarm2中也能夠看到啓動的容器:
[root@swarm2 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
794b5084af47 nginx:1.15.2 "nginx -g 'daemon of…" 4 minutes ago Up 4 minutes 80/tcp nginx
複製代碼
查看這兩臺nginx啓動的節點
[root@swarm1 system]# docker service ps nginx
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
tlewkpujja47 nginx.1 nginx:1.15.2 swarm2 Running Running 7 minutes ago
uq5pdur0cmfe nginx.2 nginx:1.15.2 swarm1 Running Running 7 minutes ago
複製代碼
Nginx集羣分別在swarm1和swarm2,經過瀏覽器訪問各個節點的nginx:192.168.18.236:80
,192.168.18.165:80
上面咱們說docker compose動態擴容是基於一臺物理機的,那麼swarm的方式能解決這個問題嗎。下面對nginx進行擴容,副本由原來的2變爲4:
[root@swarm1 system]# docker service scale nginx=4
keen_booth scaled to 4
overall progress: 4 out of 4 tasks
1/4: running [==================================================>]
2/4: running [==================================================>]
3/4: running [==================================================>]
4/4: running [==================================================>]
verify: Service converged
複製代碼
看一下擴容以後的節點分佈
[root@swarm1 system]# docker service ps nginx
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
tlewkpujja47 nginx.1 nginx:1.15.2 swarm2 Running Running 31 minutes ago
uq5pdur0cmfe nginx.2 nginx:1.15.2 swarm1 Running Running 31 minutes ago
8k507dtt3xrb nginx.3 nginx:1.15.2 swarm2 Running Running 2 minutes ago
sjiysgk5fma4 nginx.4 nginx:1.15.2 swarm1 Running Running 2 minutes ago
複製代碼
swarm1和swarm2各運行了兩個nginx容器,說明swarm方式是能夠解決單臺機器擴容問題的,在Swarm的內部也實現了高可用機制,若是某臺機器的某個服務掛掉了,他能夠內部幫咱們維護好4個副本數,保證咱們的副本數量不受環境影響。
Docker Swarm能夠實現服務平滑升級,即服務不停機更新,用戶無感知。
咱們如今先把集羣副本縮容爲2
[root@swarm1 system]# docker service scale nginx=2
nginx scaled to 2
overall progress: 2 out of 2 tasks
1/2: running
2/2: running
verify: Service converged
複製代碼
如今swarm1和swarm2上面各運行了一個nginx容器
[root@swarm1 system]# docker service ps nginx
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
tlewkpujja47 nginx.1 nginx:1.15.2 swarm2 Running Running 45 minutes ago
uq5pdur0cmfe nginx.2 nginx:1.15.2 swarm1 Running Running 45 minutes ago
複製代碼
如今的Nginx版本是1.15.2
, 如今一個一個的把他升級成最新版本的,也就是latest版本:
[root@swarm1 system]# docker service update --image nginx nginx
nginx
overall progress: 2 out of 2 tasks
1/2: running
2/2: running
verify: Service converged
複製代碼
在更新的過程當中是先更新第1個節點再更新第2個節點,在更新第1個節點的時候若是用戶請求會被轉發到第2個節點,以此來實現平滑升級,用戶無感知。咱們再來看一下升級以後運行的鏡像版本:
[root@swarm2 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
09b986422d9c nginx:latest "/docker-entrypoint.…" 11 seconds ago Up 6 seconds 80/tcp nginx
複製代碼
如今運行的已是latest版本的nginx了。
以前使用docker run
的方式運行一個容器的時候使用-v
參數指定的數據掛在是宿主機和容器之間的數據掛載,那麼咱們如今作了集羣以後,須要容器和容器之間進行數據掛載與共享。
192.168.18.171
yum -y install nfs-utils
systemctl start nfs
systemctl enable nfs
複製代碼
mkdir /nfs
/etc/exports
文件,添加內容/nfs *(insecurerw,sync,no_root_squash)
systemctl restart nfs
/nfs
目錄下隨便建立一個文件systemctl start rpcbind
mkdir /mynfs
/mynfs
目錄掛載到nfs服務器:mount -t nfs 192.168.18.171:/nfs /mynfs
核心思想
本文主要介紹了Docker在工做中的基本使用,尤爲着重講解了Docker Swarm部分,DockerSwarm算是比較重要的,雖然這部分功能被k8s代替,幾乎沒有人去用,可是k8s對於容器的編排思想和DockerSwarm仍是很像的,因此這部分也介紹的比較多,把這部分搞明白了後面再去學k8s的時候也好上手一點。另外,本人的職業是Java開發,運維這部分接觸的比較少,對於本篇文章理解的可能不夠深刻,但願你們理解一下,主要是把平時工做中接觸到的和本身學到的作了個總結,若是文章中有錯誤之處還請各位大佬提出來,我立馬改正。謝謝!
九十九次的理論不如一次的行動來得實際。