1.Docker安裝
1.如果Ubuntu自帶的Docker版本太低,我們需要卸載舊版本并安裝新的
sudo apt-get remove docker docker-engine docker.io containerd runc
2.?備份原有軟件源
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
3.選擇合適的鏡像源
# 或者使用清華大學sudo sed -i 's/http:\/\/archive\.ubuntu\.com/http:\/\/mirrors\.tuna\.tsinghua\.edu\.cn/' /etc/apt/sources.list
4.更新包信息
sudo apt updatesudo apt upgrade -y
5.安裝Docker
接下來,添加Docker官方GPG密鑰
sudo curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
添加Docker官方軟件源
sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
然后安裝Docker
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
6.配置和啟動Docker
檢查Docker版本并啟動Docker服務:
docker -v
sudo systemctl start docker
設置開機自啟
sudo systemctl enable docker
2.Docker命令解析
2.1 Docker常用命令
命令 | 說明 | 文檔地址 |
---|---|---|
docker pull | 拉取鏡像 | docker pull |
docker push | 推送鏡像到DockerRegistry | docker push |
docker images | 查看本地鏡像 | docker images |
docker rmi | 刪除本地鏡像 | docker rmi |
docker run | 創建并運行容器(不能重復創建) | docker run |
docker stop | 停止指定容器 | docker stop |
docker start | 啟動指定容器 | docker start |
docker restart | 重新啟動容器 | docker restart |
docker rm | 刪除指定容器 | docs.docker.com |
docker ps | 查看容器 | docker ps |
docker logs | 查看容器運行日志 | docker logs |
docker exec | 進入容器 | docker exec |
docker save | 保存鏡像到本地壓縮文件 | docker save |
docker load | 加載本地壓縮文件到鏡像 | docker load |
docker inspect | 查看容器詳細信息 | docker inspect |
用一副圖來表示這些命令的關系:
# Docker開機自啟
systemctl enable docker# Docker容器開機自啟
docker update --restart=always [容器名/容器id]
2.2 實踐樣例
以Nginx為例給演示上述命令:
# 第1步,去DockerHub查看nginx鏡像倉庫及相關信息# 第2步,拉取Nginx鏡像 (比較耗時)
docker pull nginx:1.20.2# 第3步,查看鏡像
docker images# 第4步,創建并允許Nginx容器
# 如果本地沒有相應鏡像,會直接從鏡像倉庫拉取鏡像
docker run -d --name nginx -p 80:80 nginx# 第5步,查看運行中容器
docker ps# 也可以加格式化方式訪問,格式會更加清爽
docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"# 第6步,訪問網頁,地址:http://虛擬機地址# 第7步,停止容器
docker stop nginx# 第8步,查看所有容器
docker ps -a --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"# 第9步,再次啟動nginx容器
docker start nginx# 第10步,再次查看容器
docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"# 第11步,查看容器詳細信息
docker inspect nginx# 第12步,進入容器,查看容器內目錄
docker exec -it nginx bash# 或者,可以進入MySQL
docker exec -it mysql mysql -uroot -p# 第13步,刪除容器
docker rm nginx# 發現無法刪除,因為容器運行中,強制刪除容器
docker rm -f nginx
解析docker run命令:
docker run -d \--name mysql \-p 3307:3306 \-e TZ=Asia/Shanghai \-e MYSQL_ROOT_PASSWORD=123 \mysql:8
1.? docker run :創建并運行一個容器
2. -d 是讓容器在后臺運行
3. --name mysql :給容器起個名字,必須唯一
4. -p 3307:3306 :設置端口映射,格式: -p 宿主機端口:容器內端口
,示例中就是將宿主機的3307映射到容器內的3306端口。容器是隔離環境,外界不可訪問。但是可以將宿主機端口映射容器內到端口,當訪問宿主機指定端口時,就是在訪問容器內的端口了。
5. -e KEY=VALUE :是設置環境變量
6. mysql:8 :指定運行的鏡像的名字,版本
鏡像的概念:
鏡像中不僅包含了軟件本身,還包含了其運行所需要的環境、配置、系統級函數庫。因此它在運行時就有自己獨立的環境,就可以跨系統運行,也不需要手動再次配置環境了。這套獨立運行的隔離環境我們稱為容器。容器內部是一個完整的Linux 文件系統,容器運行的是鏡像中自帶的環境,不依賴宿主機的環境
鏡像命名規范:
3.數據卷
3.1 數據卷介紹
數據卷(volume)是一個虛擬目錄,是容器內目錄與宿主機目錄之間映射的橋梁。
以Nginx為例,我們知道Nginx中有兩個關鍵的目錄:
-
html
:放置一些靜態資源 -
conf
:放置配置文件
如果我們要讓Nginx代理我們的靜態資源,最好是放到html
目錄;如果我們要修改Nginx的配置,最好是找到conf
下的nginx.conf
文件。
但遺憾的是,容器運行的Nginx所有的文件都在容器內部。所以我們必須利用數據卷將兩個目錄與宿主機目錄關聯,方便我們操作。
在上圖中:
-
我們創建了兩個數據卷:
conf
、html
-
Nginx容器內部的
conf
目錄和html
目錄分別與兩個數據卷關聯。 -
而數據卷conf和html分別指向了宿主機的
/var/lib/docker/volumes/conf/_data
目錄和/var/lib/docker/volumes/html/_data
目錄
這樣以來,容器內的conf
和html
目錄就 與宿主機的conf
和html
目錄關聯起來,我們稱為掛載。
此時,我們操作宿主機的/var/lib/docker/volumes/html/_data
就是在操作容器內的/usr/share/nginx/html
目錄。只要我們將靜態資源放入宿主機對應目錄,就可以被Nginx代理了。
注:/var/lib/docker/volumes
這個目錄就是默認的存放所有容器數據卷的目錄,其下再根據數據卷名稱創建新目錄,格式為/數據卷名/_data
。
為什么不讓容器目錄直接指向宿主機目錄呢?
-
因為直接指向宿主機目錄就與宿主機強耦合了,如果切換了環境,宿主機目錄就可能發生改變了。由于容器一旦創建,目錄掛載就無法修改,這樣容器就無法正常工作了。
-
但是容器指向數據卷,一個邏輯名稱,而數據卷再指向宿主機目錄,就不存在強耦合。如果宿主機目錄發生改變,只要改變數據卷與宿主機目錄之間的映射關系即可。不過,我們通過由于數據卷目錄比較深,不好尋找,通常我們也允許讓容器直接與宿主機目錄掛載而不使用數據卷
3.2 數據卷命令
命令 | 說明 | 文檔地址 |
---|---|---|
docker volume create | 創建數據卷 | docker volume create |
docker volume ls | 查看所有數據卷 | docs.docker.com |
docker volume rm | 刪除指定數據卷 | docs.docker.com |
docker volume inspect | 查看某個數據卷的詳情 | docs.docker.com |
docker volume prune | 清除數據卷 | docker volume prune |
注意:容器與數據卷的掛載要在創建容器時配置,對于創建好的容器,是不能設置數據卷的。而且創建容器的過程中,數據卷會自動創建。
演示一下nginx的html目錄掛載:
# 1.首先創建容器并指定數據卷,注意通過 -v 參數來指定數據卷
docker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx:1.20.2# 2.然后查看數據卷
docker volume ls# 3.查看數據卷詳情
docker volume inspect html# 4.查看/var/lib/docker/volumes/html/_data目錄
ll /var/lib/docker/volumes/html/_data# 5.進入該目錄,并隨意修改index.html內容
cd /var/lib/docker/volumes/html/_data
vi index.html# 6.打開頁面,查看效果# 7.進入容器內部,查看/usr/share/nginx/html目錄內的文件是否變化
docker exec -it nginx bash
-v 數據卷:容器內目錄 用此形式可以完成數據卷掛載(數據卷不存在會自動創建)。宿主機目錄固定:/var/lib/docker/volumes/數據卷名字/_data
掛載本地目錄或文件:
可以發現,數據卷的目錄結構較深,如果我們去操作數據卷目錄會不太方便。在很多情況下,我們會直接將容器目錄與宿主機指定目錄掛載。掛載語法與數據卷類似:
# 掛載本地目錄
-v 本地目錄:容器內目錄# 掛載本地文件
-v 本地文件:容器內文件
注意:本地目錄或文件必須以 /
或 ./
開頭,如果直接以名字開頭,會被識別為數據卷名而非本地目錄名。
-v mysql:/var/lib/mysql # 會被識別為一個數據卷叫mysql,運行時會自動創建這個數據卷-v ./mysql:/var/lib/mysql # 會被識別為當前目錄下的mysql目錄,運行時如果不存在會創建目錄
刪除并重新創建mysql容器,并完成本地目錄掛載:
-
掛載
/root/mysql/data
到容器內的/var/lib/mysql
目錄 -
掛載
/root/mysql/init
到容器內的/docker-entrypoint-initdb.d
目錄(初始化的SQL腳本目錄) -
掛載
/root/mysql/conf
到容器內的/etc/mysql/conf.d
目錄(這個是MySQL配置文件目錄)
docker run -d \
--name mysql \
-p 3307:3306 \
-e MYSQL_ROOT_PASSWORD=123 \
-e TZ=Asia/Shanghai \
-v /root/mysql/data:/var/lib/mysql \
-v /root/mysql/init:/docker-entrypoint-initdb.d \
-v /root/mysql/conf:/etc/mysql/conf.d \
mysql:8
4. 自定義鏡像
前面我們一直在使用別人準備好的鏡像,那如果我要部署一個Java項目,把它打包為一個鏡像該怎么做呢? 那接下來,我們就來介紹一下如何自定義鏡像。
4.1 鏡像結構
鏡像之所以能讓我們快速跨操作系統部署應用而忽略其運行環境、配置,就是因為鏡像中包含了程序運行需要的系統函數庫、環境、配置、依賴。因此,自定義鏡像本質就是依次準備好程序運行的基礎環境、依賴、應用本身、運行配置等文件,并且打包而成。
我們要從0部署一個Java應用,大概流程是這樣:
-
準備一個linux服務(CentOS或者Ubuntu均可)
-
安裝并配置JDK
-
上傳Jar包
-
運行jar包
那因此,我們打包鏡像也是分成這么幾步:
-
準備Linux運行環境(java項目并不需要完整的操作系統,僅僅是基礎運行環境即可)
-
安裝并配置JDK
-
拷貝jar包
-
配置啟動腳本
上述步驟中的每一次操作其實都是在生產一些文件(系統運行環境、函數庫、配置最終都是磁盤文件),所以鏡像就是一堆文件的集合。
但需要注意的是,鏡像文件不是隨意堆放的,而是按照操作的步驟分層疊加而成,每一層形成的文件都會單獨打包并標記一個唯一id,稱為Layer(層)。這樣,如果我們構建時用到的某些層其他人已經制作過,就可以直接拷貝使用這些層,而不用重復制作。
例如,第一步中需要的Linux運行環境,通用性就很強,所以Docker官方就制作了這樣的只包含Linux運行環境的鏡像。我們在制作java鏡像時,就無需重復制作,直接使用Docker官方提供的CentOS或Ubuntu鏡像作為基礎鏡像。然后再搭建其它層即可,這樣逐層搭建,最終整個Java項目的鏡像結構如圖所示:
4.2 Dockerfile
由于制作鏡像的過程中,需要逐層處理和打包,比較復雜,所以Docker就提供了自動打包鏡像的功能。我們只需要將打包的過程,每一層要做的事情用固定的語法寫下來,交給Docker去執行即可。而這種記錄鏡像結構的文件就稱為Dockerfile。
說明 | 示例 |
---|---|
指定基礎鏡像 |
|
設置環境變量,可在后面指令使用 |
|
拷貝本地文件到鏡像的指定目錄 |
|
執行Linux的shell命令,一般是安裝過程的命令 |
|
指定容器運行時監聽的端口,是給鏡像使用者看的 | EXPOSE 8080 |
鏡像中應用的啟動命令,容器運行時調用 | ENTRYPOINT java -jar xx.jar |
例如,要基于 centos:7 鏡像來構建一個Java應用,其Dockerfile內容如下:
# 使用 CentOS 7 作為基礎鏡像
FROM centos:7# 添加 JDK 到鏡像中
COPY jdk17.tar.gz /usr/local/
RUN tar -xzf /usr/local/jdk17.tar.gz -C /usr/local/ && rm /usr/local/jdk17.tar.gz# 設置環境變量
ENV JAVA_HOME=/usr/local/jdk-17.0.10
ENV PATH=$JAVA_HOME/bin:$PATH# 創建應用目錄
RUN mkdir -p /app
WORKDIR /app# 復制應用 JAR 文件到容器
COPY app.jar app.jar# 暴露端口
EXPOSE 8080# 運行命令
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app/app.jar"]
Dockerfile文件編寫好了之后,就可以使用如下命令來構建鏡像了。
docker build -t 鏡像名 .
-
-t :是給鏡像起名,格式依然是repository:tag的格式,不指定tag時,默認為latest
-
. :是指定Dockerfile所在目錄,如果就在當前目錄,則指定為"."
5. 網絡
首先,我們查看下MySQL容器的詳細信息,重點關注其中的網絡IP地址:
# 1.用基本命令,尋找Networks.bridge.IPAddress屬性
docker inspect mysql# 也可以使用format過濾結果
docker inspect --format='{{range .NetworkSettings.Networks}}{{println .IPAddress}}{{end}}' mysql# 得到IP地址如下:
172.17.0.2# 2.然后通過命令進入dd容器
docker exec -it dd bash# 3.在容器內,通過ping命令測試網絡
ping 172.17.0.2# 結果
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.053 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.059 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.058 ms
發現可以互聯,沒有問題。
但是,容器的網絡IP其實是一個虛擬的IP,其值并不固定與某一個容器綁定,如果我們在開發時寫死某個IP,而在部署時很可能MySQL容器的IP會發生變化,連接會失敗。
常見命令有:
命令 | 說明 |
---|---|
docker network create | 創建一個網絡 |
docker network ls | 查看所有網絡 |
docker network rm | 刪除指定網絡 |
docker network prune | 清除未使用的網絡 |
docker network connect | 使指定容器連接加入某網絡 |
docker network disconnect | 使指定容器連接離開某網絡 |
docker network inspect | 查看網絡詳細信息 |
自定義網絡:
# 1.首先通過命令創建一個網絡
docker network create itheima# 2.然后查看網絡
docker network ls# 結果:
NETWORK ID NAME DRIVER SCOPE
639bc44d0a87 bridge bridge local
403f16ec62a2 itheima bridge local
0dc0f72a0fbb host host local
cd8d3e8df47b none null local
# 其中,除了itheima以外,其它都是默認的網絡# 3.讓 myapp 和 mysql 都加入該網絡
# 3.1.mysql容器,加入 itheima 網絡
docker network connect itheima mysql# 3.2.myapp容器,也就是我們的java項目, 加入 itheima 網絡
docker network connect itheima myapp# 4.進入dd容器,嘗試利用別名訪問db
# 4.1.進入容器
docker exec -it myapp bash# 4.2.用容器名訪問
ping mysql# 結果:
PING mysql (172.18.0.2) 56(84) bytes of data.
64 bytes from mysql.itheima (172.18.0.2): icmp_seq=1 ttl=64 time=0.044 ms
64 bytes from mysql.itheima (172.18.0.2): icmp_seq=2 ttl=64 time=0.054 ms
現在無需記住IP地址也可以實現容器互聯了。
6.Docker項目部署
我們將一個SpringBoot測試項目打包為鏡像并部署
1.項目配置文件
2.項目打成jar包
3.編寫Dockerfile文件
# 第一階段:使用 Maven 鏡像構建項目
FROM maven:3.8.4-openjdk-17 AS builder# 設置工作目錄
WORKDIR /app# 復制項目的 pom.xml 和 src 目錄到容器中
COPY pom.xml .
COPY src ./src# 使用 Maven 構建項目并跳過測試
RUN mvn clean package -DskipTests# 第二階段:使用 Ubuntu 鏡像運行應用
FROM ubuntu:20.04# 安裝必要的工具(如 curl 用于健康檢查等)
RUN apt-get update && apt-get install -y \curl \&& rm -rf /var/lib/apt/lists/*# 設置工作目錄
WORKDIR /app# 從 builder 階段復制構建好的 JAR 文件到當前階段
COPY --from=builder /app/target/*.jar app.jar# 暴露端口 8080
EXPOSE 8080# 容器啟動時執行的命令
ENTRYPOINT ["java", "-jar", "app.jar"]
4.服務器配置JDK環境并將jar包和Dockerfile文件上傳到服務器項目路徑下
5.構建鏡像
docker build -t test:1.0 .
6.部署容器
docker run -d
--name test-server
-p 8080:8080
test:1.0
通過 docker logs -f 容器名
,就可以查看容器的運行日志。
這樣后端服務,就已經啟動起來了。
7.DockerCompose
家可以看到,我們部署一個簡單的java項目,其中包含3個容器:
-
MySQL
-
Nginx
-
Java項目
而稍微復雜的項目,其中還會有各種各樣的其它中間件,需要部署的東西遠不止3個。如果還像之前那樣手動的逐一部署,就太麻煩了。而Docker Compose就可以幫助我們實現多個相互關聯的Docker容器的快速部署。它允許用戶通過一個單獨的 docker-compose.yml 模板文件(YAML 格式)來定義一組相關聯的應用容器。
基本語法:
docker-compose文件中可以定義多個相互關聯的應用容器,每一個應用容器被稱為一個服務(service)。由于service就是在定義某個應用的運行時參數,因此與docker run
參數非常相似。
舉例來說,用docker run部署MySQL的命令如下:
docker run -d \
--name nginx-tlias \
-p 80:80 \
-v /usr/local/app/html:/usr/share/nginx/html \
-v /usr/local/app/conf/nginx.conf:/etc/nginx/nginx.conf \
--network itheima \
nginx:1.20.2
如果用docker-compose.yml
文件來定義,就是這樣:
services:mysql:image: "nginx:1.20.2"container_name: nginx-tliasports:- "80:80"volumes:- "/usr/local/app/html:/usr/share/nginx/html"- "/usr/local/app/conf/nginx.conf:/etc/nginx/nginx.conf"networks:- itheima
networks:itheima:name: itheima
對比如下:
docker run 參數 | docker compose 指令 | 說明 |
---|---|---|
--name | container_name | 容器名稱 |
-p | ports | 端口映射 |
-e | environment | 環境變量 |
-v | volumes | 數據卷配置 |
--network | networks | 網絡 |
services:mysql:image: mysql:8container_name: mysqlports:- "3307:3306"environment:TZ: Asia/ShanghaiMYSQL_ROOT_PASSWORD: 123volumes:- "/usr/local/app/mysql/conf:/etc/mysql/conf.d"- "/usr/local/app/mysql/data:/var/lib/mysql"- "/usr/local/app/mysql/init:/docker-entrypoint-initdb.d"networks:- tlias-nettlias:build: context: .dockerfile: Dockerfilecontainer_name: tlias-serverports:- "8080:8080"networks:- tlias-netdepends_on:- mysqlnginx:image: nginx:1.20.2container_name: nginxports:- "80:80"volumes:- "/usr/local/app/nginx/conf/nginx.conf:/etc/nginx/nginx.conf"- "/usr/local/app/nginx/html:/usr/share/nginx/html"depends_on:- tliasnetworks:- tlias-net
networks:tlias-net:name: itheima
基礎命令:
編寫好docker-compose.yml文件,就可以部署項目了。語法如下:
docker compose [OPTIONS] [COMMAND]
其中,OPTIONS和COMMAND都是可選參數,比較常見的有:
類型 | 參數或指令 | 說明 |
---|---|---|
Options | -f | 指定compose文件的路徑和名稱 |
-p | 指定project名稱。project就是當前compose文件中設置的多個service的集合,是邏輯概念 | |
Commands | up | 創建并啟動所有service容器 |
down | 停止并移除所有容器、網絡 | |
ps | 列出所有啟動的容器 | |
logs | 查看指定容器的日志 | |
stop | 停止容器 | |
start | 啟動容器 | |
restart | 重啟容器 | |
top | 查看運行的進程 | |
exec | 在指定的運行中容器中執行命令 |