最強微服務部署工具——Docker內容詳解

秋落雨微涼發表於2023-03-07

最強微服務部署工具——Docker內容詳解

在前面的內容中我們已經學習了SpringCloud的微服務搭建

但是微服務由於被分成多個部分,所以部署起來需要不同的條件環境甚至不同的作業系統從而十分繁瑣

下面我們來介紹Docker部署工具,Docker可以幫助我們快速便捷得部署常用微服務以及重複安全部署我們自己的Java專案

我們將從下面角度介紹Docker:

  • Docker概述
  • Docker基本操作
  • Docker自定義映象
  • Docker-Compose
  • Docker映象倉庫

Docker概述

首先我們先來簡單介紹一下Docker

Docker問題概述

我們分別從幾個角度來講述Docker

正常專案部署問題

那麼既然說Docker可以快速部署,那麼我們平時的部署都會存在什麼問題:

  • 首先我們一個專案需要部署的元件是非常多的,常見的包括有Java專案本身,MySQL,Nignx,GateWay,Nacos等
  • 不同的元件之間可能會存在衝突問題,比如Nacos和Eureka兩個註冊中心存在衝突問題
  • 此外在數百上千臺服務中重複部署,環境不一定一致,會遇到各種問題

此外我們還需要注意環境問題:

  • 我們不同版本的元件都需要對應不同版本的其他相容性元件,如果版本不同可能導致無法相容
  • 我們在進行開發,測試,生產時需要採用不同的環境,每種環境的配置都需要一一配置

Docker處理相容問題

因而我們的Docker就採用一種巧妙的方式去解決這個問題:

  • Docker直接將元件所需要的所有內容,包括Deps(依賴)、配置與應用一起打包
  • 並且將其封裝起來,單獨放在一個容器中,各個元件之間不會相互干擾

由此我們可以解決其相容性問題

Docker處理作業系統問題

但是我們需要注意到不同的元件所需要的底層作業系統環境可能不同,我們該如何去解決

首先我們需要了解作業系統的原理:

  • 我們目前專案部署都是基於Linux系統,但Linux又細分為CentOS、Ubuntu、Fedora等眾多版本
  • 作業系統整體分為計算機硬體(CPU、記憶體),系統核心(Linux系統,負責與底層互動),系統應用(應用、函式庫)
  • 元件主要使用系統應用的函式庫,利用函式庫呼叫系統核心對計算機硬體進行操作,也就是說根本區別只有不同環境的函式庫不同
  • 如果將一個Ubuntu版本的MySQL應用安裝到CentOS系統,MySQL在呼叫Ubuntu函式庫時,會發現找不到或者不匹配,就會報錯

所以解決方法其實很簡單:

  • Docker將使用者程式與所需要呼叫的系統函式庫一起打包
  • Docker執行到不同作業系統時,直接基於打包的函式庫,藉助於作業系統的Linux核心來執行

Docker簡述

首先我們先給出Docker的簡單定義:

  • Docker將應用的Libs(函式庫)、Deps(依賴)、配置與應用一起打包並將每個應用放到一個隔離容器去執行,避免互相干擾
  • Docker是一個市面上常用的Linux系統的專案部署工具,可以採用網路拉取或者自己搭建來快速部署專案

Docker是一個快速交付應用、執行應用的技術,具備下列優勢:

  • 可以將程式及其依賴、執行環境一起打包為一個映象,可以遷移到任意Linux作業系統
  • 執行時利用沙箱機制形成隔離容器,各個應用互不干擾
  • 啟動、移除都可以透過一行命令完成,方便快捷

Docker重要概念

我們需要介紹到Docker的兩個重要概念:

  • 映象:Docker將應用程式及其所需的依賴、函式庫、環境、配置等檔案打包在一起,稱為映象
  • 容器:映象中的應用程式執行後形成的程式就是容器,只是Docker會給容器程式做隔離,對外不可見。

我們可以把映象簡單理解為類,把容器理解為物件:

  • 我們需要注意映象一旦形成是無法修改的
  • 我們可以基於映象生成多個容器,且容器內部可以修改

DockerHub

DockerHub本質上是一個Docker映象的線上網站:

  • DockerHub:官方的Docker映象的託管平臺,這樣的平臺稱為Docker Registry
  • DockerHub同GitHub一樣用於儲存程式設計師間開源的優質Dokcer映象,其中大多是官方提供的映象
  • 為了避免這些重複勞動,人們就會將自己打包的應用映象,例如Redis、MySQL映象放到網路上,共享使用

除了國外的DockerHub外,國內也有很多優秀的Docker映象儲存網站:

我們可以在Docker Registry網站上進行映象的拉取和上傳:

Docker架構

Docker是一個Linux工具,需要進行安裝後使用,這裡就不寫Docker的安裝步驟了~

Docker是一個CS架構的程式,由兩部分組成:

  • 服務端(server):Docker守護程式,負責處理Docker指令,管理映象、容器等

  • 客戶端(client):透過命令或RestAPI向Docker服務端傳送指令。可以在本地或遠端向服務端傳送指令。

Docker基本操作

下面我們來介紹Docker的基本操作

Docker映象操作

我們首先需要了解映象的組成元素:

  • 構造:[repository]:[tag]

  • 案例:mysql:5.7

  • 說明:其中repository是指映象名稱,tag是指版本號

我們首先給出一張docker映象整體操作圖:

然後我們給出Docker的相關操作:

# Docker檢視目前存在映象
docker images

# Docker存在兩種獲取方式(pull雲端獲取,build構建我們後續詳細講述)

## Docker的pull拉取映象,直接在雲伺服器上拉取(一般可以在雲伺服器上搜尋對應的元件,然後獲得其對應版本號或對應拉取程式碼)
## 若標記版本號則為對應版本號,若未標記則為最新版本lastest
docker pull [repository]
docker pull [repository]:[tag]

# Docker的刪除rmi(remove images)
docker rmi [repository]:[tag]

# Docker也可以透過push方法推送到伺服器上
docker push [repository]:[tag]

# Docker可以採用save將其變換為jar包
docker save -o [儲存的目標檔名稱] [映象名稱]

# Docker可以採用load將jar包轉換回映象
docker load -i [目標檔名稱]

# 最後我們給出一個help方法可以用於檢視所有的Docker引數設定
docker 操作名稱 --help

Docker容器操作

我們首先給出一張dokcer容器操作的整體流程圖:

首先我們需要知道容器的三個狀態:

  • 執行:程式正常執行
  • 暫停:程式暫停,CPU不再執行,並不釋放記憶體
  • 停止:程式終止,回收程式佔用的記憶體、CPU等資源

然後我們來簡單介紹一下上述操作:

# ------------------------------------------

# 建立並執行一個容器,處於執行狀態
docker run 

# 容器暫停
docker pause

# 容器執行
docker unpause

# 容器停止
docker stop

# 容器執行
docker start

# 刪除容器
docker rm

# 進入容器執行命令
docker exec

# 檢視容器執行日誌
docker logs

# 檢視所有執行中的容器
docker ps

# ------------------------------------------

下面我們挑幾個常用操作去詳細介紹:

# run 執行方法
docker run --name containerName -p 80:80 -d nginx

docker run:		語法
--name:		後面跟容器名稱
--p:		後面跟對應埠號,第一個埠號是宿主機埠,第二個是容器埠
			(第一個是虛擬機器埠號,你需要從這個虛擬機器埠號進入,然後進入到對應容器埠號中去呼叫該元件)
			 預設情況下,容器是隔離環境,我們直接訪問宿主機的80埠,肯定訪問不到容器中的nginx。
			現在,將容器的80與宿主機的80關聯起來,當我們訪問宿主機的80埠時,就會被對映到容器的80,這樣就能訪問到nginx了:
-d:			後臺執行
nginx:		映象名稱

# ps 執行方法
docker ps # 檢視執行中容器
docker -a ps # 檢視所有容器

# logs 執行方法
docker logs # 獲取當前日誌
docker -f logs # 實時檢視日誌

# exec 執行方法
docker exec -it containerName bash

docker exec :	進入容器內部,執行一個命令
-it : 			 給當前進入的容器建立一個標準輸入、輸出終端,允許我們與容器互動(可以看成預設格式)
containerName :	要進入的容器的名稱
bash:			進入容器後執行的命令,bash是一個linux終端互動命令

注意:在進入容器之後,容器內部實際上是一個小的虛擬機器環境,但很多高階命令都無法使用,例如vim等內容書寫命令無法使用
注意:我們在進入容器修改資訊,例如修改Nginx的html檔案等,我們可以在Docker線上網站找到對應的位置直接進入書寫(不推薦)

Docker資料卷操作

我們首先來介紹一下資料卷:

  • 資料卷(volume)是一個虛擬目錄,指向宿主機檔案系統中的某個目錄。
  • 我們可以採用資料卷掛卷,透過對宿主機的某個檔案進行修改從而修改容器中的資料或者儲存容器的資料

下面我們來介紹資料卷的具體操作:

# 資料卷基本格式
docker volume [command]

docker volume命令是資料卷操作,根據命令後跟隨的command來確定下一步的操作:

- create 	建立一個volume
- inspect 	顯示一個或多個volume的資訊(顯示資料卷存在位置)
- ls 		列出所有的volume
- prune 	刪除未使用的volume
- rm 		刪除一個或多個指定的volume

# 建立資料卷
docker volume create [name]

docker volume create html

# 檢視當前資料卷
docker volume ls

# 檢視某個資料卷的詳細資訊(具體包括:名字,地址等)
docker volume inspect [name]

docker volume inspect html

# 刪除指定資料卷
docker rm [name]

# 刪除所有未使用的資料卷
docker prune

我們在瞭解資料卷操作後還需要了解如何掛卷:

# 掛卷一般在建立docker容器時(下面的"\"是換行符)
docker run \
  --name mn \
  -v html:/root/html \ # -v就是掛卷,:前是資料卷名稱,:後是具體的容器檔案位置
  -p 8080:80
  nginx \
  
# 掛卷後我們就可以對其進行修改

# 檢視html資料卷的位置
docker volume inspect html
# 進入該目錄
cd /var/lib/docker/volumes/html/_data
# 修改檔案
vi index.html

除了直接掛卷資料卷外我們也可以直接掛卷檔案位置:

# 我們可以直接指定檔案位置從而減少一次資料卷建立過程同時直接指定建立位置便於管理
docker run \
  --name mysql \
  -v /var/lib/docker/volumes/html:/root/html \ # -v就是掛卷,:前是資料卷名稱,:後是具體的容器檔案位置
  -p 8080:80
  mysql \
  
# - -v [宿主機目錄]:[容器內目錄]
# - -v [宿主機檔案]:[容器內檔案]

我們這裡給出兩種掛卷方式的優劣點:

  • 資料卷掛載耦合度低,由docker來管理目錄,但是目錄較深,不好找
  • 目錄掛載耦合度高,需要我們自己管理目錄,不過目錄容易尋找檢視

Dockerfile自定義映象

這小節我們來介紹Dokcerfile,也就是docker的Build建立方法

映象結構介紹

首先我們需要了解映象:

  • 映象是將應用程式及其需要的系統函式庫、環境、配置、依賴打包而成
  • 映象是在系統函式庫、執行環境基礎上,新增應用程式檔案、配置檔案、依賴檔案等組合,編寫好啟動指令碼打包在一起形成的檔案

我們這裡給出MySQL的映象圖示:

Dockerfile介紹

我們首先來介紹一下dockerfile:

  • dockerfile實際上是一個shell指令碼,裡面書寫了映象構造的具體條件
  • 映象構造的基本條件就是基於映象的結構一層層書寫得出的,也就是說dockerfile實際上就是搭配各個環境建立映象
  • 我們需要告訴Docker,我們的映象的組成,需要哪些BaseImage、需要複製什麼檔案、需要安裝什麼依賴、啟動指令碼是什麼
  • Dockerfile就是一個文字檔案,其中包含一個個的指令,用指令來說明要執行什麼操作來構建映象。每一個指令都會形成一層Layer。

我們給出dockerfile的基本語法:

指令 說明 示例
FROM 指定基礎映象 FROM centos:6
ENV 設定環境變數,可在後面指令使用 ENV key value
COPY 複製本地檔案到映象的指定目錄 COPY ./mysql-5.7.rpm /tmp
RUN 執行Linux的shell命令,一般是安裝過程的命令 RUN yum install gcc
EXPOSE 指定容器執行時監聽的埠,是給映象使用者看的 EXPOSE 8080
ENTRYPOINT 映象中應用的啟動命令,容器執行時呼叫 ENTRYPOINT java -jar xx.jar

我們這裡給出Dockerfile的官方傳送門:

Dockerfile具體使用

我們給出一個Dockerfile案例來詳細解釋Dockerfile語法:

# 注意:我們首先需要一個dockerfile資料夾,裡面裝有/jdk8.tar.gz以及/docker-demo.jar,當然還有下述的dockerfile

# --------------下述為dockerfile檔案--------------

# 指定基礎映象
FROM ubuntu:16.04
# 配置環境變數,JDK的安裝目錄
ENV JAVA_DIR=/usr/local

# 複製jdk和java專案的包
COPY ./jdk8.tar.gz $JAVA_DIR/
COPY ./docker-demo.jar /tmp/app.jar

# 安裝JDK
RUN cd $JAVA_DIR \
 && tar -xf ./jdk8.tar.gz \
 && mv ./jdk1.8.0_144 ./java8

# 配置環境變數
ENV JAVA_HOME=$JAVA_DIR/java8
ENV PATH=$PATH:$JAVA_HOME/bin

# 暴露埠
EXPOSE 8090
# 入口,java專案的啟動命令
ENTRYPOINT java -jar /tmp/app.jar

# 最後我們需要build該檔案
docker build -t javaweb:1.0 .

-t:		給映象加一個Tag
javaWeb:映象名
1.0:	映象版本
.:		Dockerfile所在目錄(.就是指當前目錄)

我們可以注意到上述dockerfile中配置了jdk8環境和java專案,而我們可以透過更換基礎映象省略jdk8的配置:

# 我們直接基於java:8-alpine環境(該環境下已配置jdk8),我們只需要將java專案複製複製並啟動
FROM java:8-alpine
COPY ./app.jar /tmp/app.jar
EXPOSE 8090
ENTRYPOINT java -jar /tmp/app.jar

Docker-Compose

下面我們來詳細介紹一下Docker-Compose

Docker-Compose簡述

首先我們先來簡單介紹一下Docker-Compose:

  • Docker Compose可以基於Compose檔案幫我們快速的部署分散式應用
  • Compose檔案是一個文字檔案,透過指令定義叢集中的每個容器如何執行
  • DockerCompose檔案可以看做是將多個docker run命令寫到一個檔案,語法格式類似於yml格式

我們給出一個簡單的Docker-Compose檔案:

# -----------------檔案概述-----------------
描述一個專案,其中包含兩個容器:

- mysql:一個基於`mysql:5.7.25`映象構建的容器,並且掛載了兩個目錄
- web:一個基於`docker build`臨時構建的映象容器,對映埠時8090

# -----------------檔案內容-----------------

version: "3.8" 	# 版本號
 services:		# 服務標識(下述均為服務名稱)
  mysql:		# MySQL服務(不需要對映埠,因為只在內部使用)
    image: mysql:5.7.25	# 依賴映象
    environment:		# 環境變數,這裡直接書寫了MySQL密碼
     MYSQL_ROOT_PASSWORD: 123 
    volumes:			# 掛卷
     - "/tmp/mysql/data:/var/lib/mysql"
     - "/tmp/mysql/conf/hmy.cnf:/etc/mysql/conf.d/hmy.cnf"
  web:			# Web服務
    build: .	# 依賴當前資料夾下的dockerfile檔案
    ports:		# 對映埠
     - "8090:8090"
    

DockerCompose的詳細語法參考官網:https://docs.docker.com/compose/compose-file/

溫馨提醒:Docker-Compose也需要下載使用,這裡不做贅述

Docker-Compose部署微服務叢集

下面我們詳細介紹一下微服務叢集的部署:

  1. 建立spring-cloud的資料夾,包含我們需要部署的元件資料夾和Docker-Compose檔案,每個資料夾包含本身的Dockerfile檔案

  1. 展示docker-compose和dockerfile檔案
# ------------------docker-compose檔案------------------

version: "3.2"	# 版本

services:
  nacos:	# nacos註冊中心
    image: nacos/nacos-server	# 映象
    environment:
      MODE: standalone	# 環境:單點模式啟動
    ports:
      - "8848:8848"	# 對映埠
  mysql:	# MySQL資料庫
    image: mysql:5.7.25		# 映象
    environment:
      MYSQL_ROOT_PASSWORD: 123	# 環境:設定密碼
    volumes:		# 掛卷,方便修改配置
      - "$PWD/mysql/data:/var/lib/mysql"
      - "$PWD/mysql/conf:/etc/mysql/conf.d/"
  userservice:		# 基於dockerfile建立臨時專案
    build: ./user-service
  orderservice:		# 基於dockerfile建立臨時專案
    build: ./order-service
  gateway:			# 基於dockerfile建立臨時專案
    build: ./gateway
    ports:
      - "10010:10010"
      
# ------------------dockerfile檔案------------------

FROM java:8-alpine	# 基於java:8-alpine環境
COPY ./app.jar /tmp/app.jar	# 複製當前資料夾中的app.jar至虛擬機器中的/tmp資料夾下命名為app.jar
ENTRYPOINT java -jar /tmp/app.jar # 啟動該映象時以java -jar啟動/tmp/app.jar
  1. 修改微服務配置
# 因為微服務將來要部署為docker容器,而容器之間互聯不是透過IP地址,而是透過容器名。
# 這裡我們將order-service、user-service、gateway服務的mysql、nacos地址都修改為基於容器名的訪問。

spring:
  datasource:
    url: jdbc:mysql://mysql:3306/cloud_order?useSSL=false
    username: root
    password: 123
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: orderservice
  cloud:
    nacos:
      server-addr: nacos:8848 # nacos服務地址
  1. 修改打包名稱
<!--在pom.xml中修改,注意:需要部署的專案都需要修改,因為我們的docker-compose中將app.jar複製並建立容器時啟動-->

<build>
  <!-- 服務打包的最終名稱 -->
  <finalName>app</finalName>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
  </plugins>
</build>
  1. 將jar包複製到對應資料夾下,並將spring-cloud資料夾複製到虛擬機器中啟動即可
# 啟動docker-compose
docker-compose up -d

Docker映象倉庫

最後我們介紹一下Docker的私服映象搭建

Docker搭建私有映象倉庫(簡單版)

不管如何搭建映象倉庫,我們都是基於Docker官方提供的DockerRegistry來實現的:

搭建簡單版的私有映象倉庫很簡單,我們只需要輸入下述docker run程式碼即可:

docker run -d \
    --restart=always \
    --name registry	\
    -p 5000:5000 \
    -v registry-data:/var/lib/registry \ # 這是私有映象庫存放資料的目錄
    registry

Docker搭建私有映象倉庫(圖形化)

圖形化私有映象的搭建不是官方所提供的,而是基於一個元件,我們需要使用到Docker-Compose:

version: '3.0'
services:
  registry:	# 服務名
    image: registry	# 映象名
    volumes:	# 掛卷,存放資料的位置
      - ./registry-data:/var/lib/registry
  ui:	# ui就是圖形化介面元件
    image: joxit/docker-registry-ui:static	# 映象名
    ports:
      - 8080:80	# 開放埠,系統透過8080訪問到ui的80埠,然後進入到registry的5000埠
    environment:
      - REGISTRY_TITLE=私有倉庫	# 倉庫名稱
      - REGISTRY_URL=http://registry:5000	# registry是服務名稱,5000是registry的服務埠號
    depends_on:
      - registry

Docker信任地址配置

我們的私服採用的是http協議,預設不被Docker信任,所以需要做一個配置:

# 開啟要修改的檔案
vi /etc/docker/daemon.json
# 新增內容:
"insecure-registries":["http://192.168.150.101:8080"]
# 重載入
systemctl daemon-reload
# 重啟docker
systemctl restart docker

Docker推送、拉取映象

私服的拉取需要我們提前設定tag才能夠進行推送:

# 重新tag本地映象,名稱字首為私有倉庫的地址:192.168.150.101:8080/
docker tag nginx:latest 192.168.150.101:8080/nginx:1.0 

# 推送映象
docker push 192.168.150.101:8080/nginx:1.0 

# 拉取映象
docker pull 192.168.150.101:8080/nginx:1.0 

結束語

這篇文章中介紹了Docker的內容及其附屬產品Dockerfile和Docker-Compose,希望能為你帶來幫助

附錄

該文章屬於學習內容,具體參考B站黑馬程式設計師的微服務課程

這裡附上影片連結:01-今日課程介紹3_嗶哩嗶哩_bilibili

相關文章