Docker基本使用與服務編排

安裝Docker

安裝Docker的環境要求html

  1. Linux的內核版本要求3.10以上

使用以下命令查看內核版本java

uname -r
複製代碼

執行下面的命令開始安裝Docker

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使用

使用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的網絡模式

上面的例子跑的很順利,可是咱們忽略了一個細節:爲何經過宿主機映射出來的端口能夠訪問到容器呢,這就涉及到了Docker的網絡模式:

  1. 網橋模式(默認):此模式會爲每個容器分配Network Namespace、設置IP等,並將並將一個主機上的Docker容器鏈接到一個虛擬網橋上,在宿主機執行指令ifconfig能夠看到,多了一個docker0虛擬網卡,默認網關即是docker的IP地址,在主機上建立一對虛擬網卡veth pair設備,Docker將veth pair設備的一端放在新建立的容器中,並命名爲eth0(容器的網卡),另外一端放在主機中,以vethxxx這樣相似的名字命名,並將這個網絡設備加入到docker0網橋中
  2. 容器模式:指定新建立的容器和已經存在的一個容器共享一個Network Namespace,而不是和宿主機共享。新建立的容器不會建立本身的網卡,配置本身的IP,而是和一個指定的容器共享IP、端口範圍等。一樣,兩個容器除了網絡方面,其餘的如文件系統、進程列表等仍是隔離的。兩個容器的進程能夠經過lo網卡設備通訊。
  3. 主機模式:一個Network Namespace提供了一份獨立的網絡環境,包括網卡、路由、Iptable規則等都與其餘的Network Namespace隔離。一個Docker容器通常會分配一個獨立的Network Namespace。但若是啓動容器的時候使用host模式,那麼這個容器將不會得到一個獨立的Network Namespace,而是和宿主機共用一個Network Namespace。容器將不會虛擬出本身的網卡,配置本身的IP等,而是使用宿主機的IP和端口。
  4. NONE模式:Docker容器擁有本身的Network Namespace,可是,並不爲Docker容器進行任何網絡配置。

服務容器化

服務容器化須要依賴一個Dockerfile的打包文件,文件的編寫格式以下:

  1. FROM: 第一條指令必須爲FROM指令,用於指定基礎鏡像。
  2. MAINTAINER: 指定維護者信息。
  3. RUN: 會在shell終端運行命令。
  4. EXPOSE: 聲明容器須要暴露的端口號。
  5. ENV: 指定一個環境變量,能夠被後續的RUN引用,而且在容器中記錄該環境變量。
  6. ADD: 該命令將複製指定的到容器中的。 其中能夠是Dockerfile所在目錄的一個相對路徑;也能夠是tar文件(自動解壓)。
  7. VOLUME: 格式爲 VOLUME [path]。 建立一個能夠從本地主機或其餘容器掛載點,通常用來存放須要保持的數據。
  8. USER: 指定運行容器時的用戶名,後續的RUN也會指定該用戶。
  9. WORKDIR: 指定工做空間,後續命令都在此目錄下執行。
  10. CMD: docker啓動後要執行的命令,能夠在啓動的時候覆蓋。
  11. ENTRYPOINT: docker啓動後要執行的命令,沒法被覆蓋,只能追加。

1. 手動構建

先來編寫一個最簡單的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是用來構建鏡像的一個模板,可使用他來構建咱們本身的應用程序,這種方式能夠很方便的進行服務容器化部署,這種方式是手動在服務器上進行構建;

2. Maven的Docker插件構建

手動構建的方式大量的工做量在運維同窗,並且運維同窗還須要知道你的服務依賴的基礎鏡像和容器內的日誌目錄,這部分的工做開發比較熟,使用maven集成的docker打包插件能夠把容器化的過程放在開發這邊,運維只須要跑一整條命令便可

  • 在項目中引入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
複製代碼

Docker的鏡像倉庫

基本搭建

在本身的公司內部搭建鏡像倉庫,存放公司本身的鏡像(相似於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

Docker構建微服務與動態擴容

1. Docker Compose

1. 1. 什麼是Docker Compose

在微服務架構中,咱們須要打包的服務不少,規模通常的狀況下得有30多個微服務,在線上可能還要根據實際狀況動態擴縮容,不可能一個一個的進行build,這時候咱們須要對微服務項目進行統一管理。

1. 2. Docker Compose管理容器的結構

Docker Compose將所管理的容器分爲三層,分別是工程( project),服務(service)以及容器( container)。 Docker Compose運行目錄下的全部文件( docker-compose.yml、 extends文件或環境變量文件等)組成一個工程(默認爲 docker-compose.yml所在目錄的目錄名稱)。一個工程可包含多個服務,每一個服務中定義了容器運行的鏡像、參數和依賴,一個服務可包括多個容器實例。 同一個docker compose內部的容器之間能夠用服務名相互訪問,服務名就至關於hostname,能夠直接 ping 服務名,獲得的就是服務對應容器的ip,若是服務作了擴容,一個服務對應了多個容器,則 ping 服務名 會輪詢訪問服務對應的每臺容器ip ,docker底層用了LVS等技術幫咱們實現這個負載均衡。

1.3. 使用

  • 安裝
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
複製代碼
  • 弄幾個微服務項目,一個微服務對應一個文件夾,我這裏有3個:
[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
複製代碼
  • 上面說過,compose的結構最外層是工程,因此咱們在工程下建立一個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. Docker Swarm

1. Swarm結構搭建

準備2臺物理機:

  • 192.168.18.236 ->> swarm1
  • 192.168.18.165 ->> swarm2

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是從節點

2. 集羣節點中部署應用

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:80192.168.18.165:80

3. 集羣節點動態擴容

上面咱們說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個副本數,保證咱們的副本數量不受環境影響。

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了。

5. 集羣數據持久化

以前使用docker run 的方式運行一個容器的時候使用-v參數指定的數據掛在是宿主機和容器之間的數據掛載,那麼咱們如今作了集羣以後,須要容器和容器之間進行數據掛載與共享。

  1. 單獨搞一臺機器作NFS 192.168.18.171
  2. 在每臺機器上面都安裝nfs-utils yum -y install nfs-utils
  3. 在nfs機器啓動nfs服務
systemctl start nfs
systemctl enable nfs
複製代碼
  1. 在nfs上建立一個文件共享的目錄 mkdir /nfs
  2. 編輯 /etc/exports文件,添加內容/nfs *(insecurerw,sync,no_root_squash)
  3. 重啓nfs systemctl restart nfs
  4. /nfs目錄下隨便建立一個文件
  5. 在其餘兩個swarm機器上執行systemctl start rpcbind
  6. 在其餘兩個swarm機器上建立文件夾,存放容器內的掛載數據mkdir /mynfs
  7. 將swarm機器的/mynfs目錄掛載到nfs服務器:mount -t nfs 192.168.18.171:/nfs /mynfs

核心思想

  1. swarm1建立一個數據卷將容器掛載到宿主機
  2. 將swarm1宿主機的數據卷掛載到nfs進行數據共享

總結

本文主要介紹了Docker在工做中的基本使用,尤爲着重講解了Docker Swarm部分,DockerSwarm算是比較重要的,雖然這部分功能被k8s代替,幾乎沒有人去用,可是k8s對於容器的編排思想和DockerSwarm仍是很像的,因此這部分也介紹的比較多,把這部分搞明白了後面再去學k8s的時候也好上手一點。另外,本人的職業是Java開發,運維這部分接觸的比較少,對於本篇文章理解的可能不夠深刻,但願你們理解一下,主要是把平時工做中接觸到的和本身學到的作了個總結,若是文章中有錯誤之處還請各位大佬提出來,我立馬改正。謝謝!

九十九次的理論不如一次的行動來得實際。

相關文章
相關標籤/搜索