提綱:Docker和Kubernetes關系

本人開始今天分享之前想提以前簡單的問題,大家可以試試回答,Kubernetes和Docker關系?
Kubernetes的作用是管理容器,docker一旦變多,重啟,容器通信等一系列程序就需要一個工具來進行管理,這就是Kubernetes做的事情

K8S 調度的基本單位為 pod(一個POD表示一個或多個容器),為什么基本單位不是一個容器?
Docker概述
Docker是什么?
? Docker 是一個開源專案,誕生于 2013 年初,最初是 dotCloud 公司內部的一個業余專案,它基于 Google 公司推出的Go語言實作,專案后來加入了 Linux 基金會,遵從了 Apache 2.0 協議,專案代碼在GitHub 上進行維護,
? Docker 專案的目標是實作輕量級的作業系統虛擬化解決方案,Docker 的基礎是 Linux 容器(LXC)等技術,在 LXC 的基礎上 Docker 進行了進一步的封裝,讓用戶不需要去關心容器的管理,使得操作更為簡便,用戶操作 Docker 的容器就像操作一個快速輕量級的虛擬機一樣簡單,
既然是都是虛擬化技術, 為什么不直接使用虛擬機?
| 序號 | Docker | 虛擬機 |
|---|---|---|
| 1 | 占用資源少 | 資源占用多 |
| 2 | 操作簡單 | 冗余步驟多 |
| 3 | 啟動快 | 啟動慢 |

備注:區分容器和虛擬機概念(容器起源自Linux Containers(LXC)一種新的虛擬化技術)
-
容器內應用行程直接運行于宿主內核是對行程進行隔離的技術、包含完整檔案系統,并區分計算資源、自身無內核、無需硬體虛擬,
-
虛擬機在虛擬出一套硬體后在其基礎上搭建套作業系統,后運行軟體,
(補充)為什么Docker比較 VM 快?
1、docker有著比虛擬機更少的抽象層,由亍docker不需要Hypervisor實作硬體資源虛擬化,運行在docker容器上的程式直接使用的都是實際物理機的硬體資源,因此在CPU、記憶體利用率上docker將會在效率上有明顯優勢,
2 、docker利用的是宿主機的內核,而不需要Guest OS,因此,當新建一個容器時,docker不需要和虛擬機一樣重新加載一個作業系統內核,仍而避免引尋、加載作業系統內核返個比較費時費資源的程序,當新建一個虛擬機時,虛擬機軟體需要加載Guest OS,返個新建程序是分鐘級別的,而docker由于直接利用宿主機的作業系統,則省略了返個程序,因此新建一個docker容器只需要幾秒鐘,
容器化技術給開發/運維(DevOps)/部署能帶來哪些便捷?
| 序號 | 維度 | Docker開發/運維 | 傳統開發/運維 |
|---|---|---|---|
| 1 | 應用交付和部署 | 少量容器鏡像檔案(組態檔內置) | 復雜的安裝程式和配置說明檔案 |
| 2 | 升級、遷移、擴縮容 | 通過鏡像運行新的容器進行快速擴容 | 重新部署上線 |
| 3 | 系統運維 | 生產、開發、測驗環境高度一致; 組態檔封裝; 測驗快速定位、修復; 更快速的交付和部署; 更簡單的管理; 更快速的啟動時間 | 生產、開發、測驗環境高不一致; 管理、交付、部署難度大; 虛擬機啟動時間慢 |
| 4 | 資源利用 | 內核級虛擬化; 一臺物理機上可以運行很多個容器實體; 提升物理服務器的CPU和記憶體的利用率; | 傳統的虛擬化技術需要額外Hypervisor |

Docker是怎么作業的?

Docker是一個Client-Server結構的系統,Docker守護行程運行在主機上, 然后通過Socket連接從客戶端訪問,守護行程從客戶端接受命令并管理運行在主機上的容器, 容器,是一個運行時環境,就是我們 前面說到的集裝箱,
備注:
- Docker官網:http://www.docker.com
- Docker中文網站:https://www.docker-cn.com
- Docker Hub官網:https://hub.docker.com (倉庫)
?
Docker安裝
Docker組成

備注:區分鏡像和容器
-
鏡像(image):Docker 鏡像(Image)就是一個只讀的模板,鏡像可以用來創建 Docker 容器,一個鏡像可以創建很多容器, 就好似 Java 中的 類和物件,類就是鏡像,容器就是物件!
-
容器(container):Docker 利用容器(Container)獨立運行的一個或一組應用,容器是用鏡像創建的運行實體, 它可以被啟動、開始、停止、洗掉,每個容器都是相互隔離的,保證安全的平臺,可以把容器看做是一個簡易版的 Linux 環境(包括root用戶權限、行程空間、用戶空間和網路空間等) 和運行在其中的應用程式,
-
倉庫(repository):倉庫(Repository)是集中存放鏡像檔案的場所, 倉庫(Repository)和倉庫注冊服務器(Registry)是有區別的,倉庫注冊服務器上往往存放著多個倉庫,每個倉庫中又包含了多個鏡像,每個鏡像有不同的標簽(tag), 倉庫分為公開倉庫(Public)和私有倉庫(Private)兩種形式,最大的公開倉庫是 Docker Hub(https://hub.docker.com/),存放了數量龐大的鏡像供用戶下載, 國內的公開倉庫包括阿里云 、網易云等

補充:容器的定義和鏡像幾乎一模一樣,也是一堆層的統一視角,唯一區別在于容器的最上面那一層是可讀可寫的,
Docker安裝
官網安裝參考手冊:https://docs.docker.com/engine/install/centos/
1、yum安裝gcc相關環境(需要確保 虛擬機可以上外網 )
yum -y install gcc
yum -y install gcc-c++
2 、卸載舊版本
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
3、安裝需要的YUM軟體包
yum install -y yum-utils
4、設定鏡像倉庫
# 正確推薦使用國內的
yum-config-manager --add-repo http://mirrors.aliyun.com/docker- ce/linux/centos/docker-ce.repo
5、更新yum軟體包索引
yum makecache fast
6、安裝 Docker CE
yum install docker-ce docker-ce-cli containerd.io
7、啟動Docker
systemctl start docker
8、卸載Docker
systemctl stop docker
yum -y remove docker-ce docker-ce-cli containerd.io
rm -rf /var/lib/docker
Docker常用命令
基本命令
docker version # 顯示 Docker 版本資訊,
docker info # 顯示 Docker 系統資訊,包括鏡像和容器數,,
docker --help # 幫助
docker images # 列出本地主機上的鏡像
# 備注:同一個倉庫源可以有多個 TAG,代表這個倉庫源的不同版本,我們使用REPOSITORY:TAG 定義不同 的鏡像,如果你不定義鏡像的標簽版本,docker將默認使用 lastest 鏡像!
docker search mysql # 搜索鏡像
docker pull mysql/mysql:8.0 # 下載鏡像
docker pull centos # 下載容器
docker rmi -f 鏡像id # 洗掉單個
docker rmi -f 鏡像名:tag 鏡像名:tag # 洗掉多個
docker rmi -f $(docker images -qa) # 洗掉全部
docker run -it centos /bin/bash # 新建容器并啟動
docker ps # 列出所有運行的容器
docker start (容器id or 容器名) # 啟動容器
docker restart (容器id or 容器名) # 重啟容器
docker stop (容器id or 容器名) # 停止容器
docker kill (容器id or 容器名) # 強制停止容器
docker rm 容器id # 洗掉指定容器
docker rm -f $(docker ps -a -q) # 洗掉所有容器
docker ps -a -q|xargs docker rm # 洗掉所有容器
# 從容器內拷貝檔案到主機上
docker cp 容器id:容器內路徑 目的主機路徑
docker commit 提交容器副本使之成為一個新的鏡像!
# 語法
docker commit -m="提交的描述資訊" -a="作者" 容器id 要創建的目標鏡像名:[標簽名]
# 例子
docker run -d centos # 啟動centos,使用后臺方式啟動
docker inspect 容器id
# 語法:
# -d 后臺運行
# -p 埠
# -v 容器資料卷
# -i 以互動模式運行容器,通常與 -t 同時使用
# -t 為容器重新分配一個偽輸入終端,通常與 -i 同時使用
# -d 后臺運行容器,并回傳容器ID
# -itd 組合命
# 容器進入:
docker exec -it --user root docker-nginx /bin/bash
# 檔案向容器復制:
# 語法:docker cp 容器外路徑 容器ID:容器內路徑
docker cp 外部檔案地址 e7f25fc3bd48:容器內檔案地址
# Nginx:
docker run -d -p 80:80 -v 外部檔案地:容器內檔案地址 --name docker-nginx nginx
# MySQL:
docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name docker-mysql mysql:8.0
# Redis:
docker run -itd --name docker-redis -p 6379:6379 redis
# RabbitMQ:
docker pull rabbitmq
docker pull rabbitmq:management
docker run -d --name docker-rabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p 25672:25672 -p 15671:15671 -p 15672:15672 rabbitmq:management
練習:
docker search nginx
docker pull nginx
docker images
docker run -d --name mynginx -p 3500:80 nginx
docker ps
curl localhost:3500
docker exec -it mynginx /bin/bash
whereis nginx # 尋找nginx
cd /usr/share/nginx # nginx 的路徑
vim index.html #修改index
可視化/管理工具

Portainer
docker run -d -p 8088:9000 \
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --
privileged=true portainer/portainer
Portainer是Docker的圖形化管理工具,提供狀態顯示面板、應用模板快速部署、容器鏡像網路資料卷的基本操作(包括上傳下載鏡像,創建容器等操作)、事件日志顯示、容器控制臺操作、Swarm集群和服務等集中管理和操作、登錄用戶管理和控制等功能,功能十分全面,面向中小型單位對容器管理的全部需求,
訪問方式:http://IP:8088
首次登陸需要注冊用戶,給admin用戶設定密碼:單機版這里選擇local即可,選擇完畢,點擊Connect即可連接到本地docker:
Docker Dasktop

Docker鏡像原理
鏡像是什么?
鏡像是一種輕量級、可執行的獨立軟體包,用來打包軟體運行環境和基于運行環境開發的軟體,它包含運行某個軟體所需的所有內容,包括代碼、運行時、庫、環境變數和組態檔,
Docker鏡像加載原理
在聊這個話題時候需要提前了解兩個知識點,什么是UnionFS ?有興趣可以去了解一下,這里只做簡單闡述,
? UnionFS(聯合檔案系統):Union檔案系統(UnionFS)是一種分層、輕量級并且高性能的檔案系統,它支持對檔案系統的修改作為一次提交來一層層的疊加,同時可以將不同目錄掛載到同一個虛擬檔案系統下(unite several directories into a single virtual filesystem),Union 檔案系統是 Docker 鏡像的基礎,鏡像可以通過分層來進行繼承,基于基礎鏡像(沒有父鏡像),可以制作各種具體的應用鏡像,
特性:一次同時加載多個檔案系統,但從外面看起來,只能看到一個檔案系統,聯合加載會把各層檔案系統疊加起來,這樣最終的檔案系統會包含所有底層的檔案和目錄
UnionFS和Docker鏡像加載原理有什么關系?

docker的鏡像實際上由一層一層的檔案系統組成,這種層級的檔案系統UnionFS,bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引導加載kernel, Linux剛啟動時會加載bootfs檔案系統,在Docker鏡像的最底層是bootfs,這一層與我們典型的Linux/Unix系統是一樣的,包含boot加載器和內核,當boot加載完成之后整個內核就都在記憶體中了,此時記憶體的使用權已由bootfs轉交給內核,此時系統也會卸載bootfs,bootfs (root file system) ,在bootfs之上,包含的就是典型 Linux 系統中的 /dev, /proc, /bin, /etc 等標準目錄和檔案,rootfs就是各種不同的作業系統發行版,比如Ubuntu,Centos等等,
平時我們安裝進虛擬機的CentOS都是好幾個G,為什么Docker這里才200M?
對于一個精簡的OS,rootfs 可以很小,只需要包含最基本的命令,工具和程式庫就可以了,因為底層直接用Host的kernel,自己只需要提供rootfs就可以了,由此可見對于不同的linux發行版, bootfs基本是一致的, rootfs會有差別, 因此不同的發行版可以公用bootfs,
備注: Linuxkernel是一個一體化內核(monolithic kernel)系統,提供硬體抽象層、磁盤及檔案系統控制、多任務等功能的系統軟體,不是一套完整的作業系統,有興趣可以去閱讀: Linux內核的作業原理
Docker檔案分層原理
分層的鏡像:我們可以去下載一個鏡像,注意觀察下載的日志輸出,可以看到是一層一層的在下載!

為什么Docker鏡像要采用這種分層的結構呢?
最大的好處,我覺得莫過于是資源共享了!比如有多個鏡像都從相同的Base鏡像構建而來,那么宿主機只需在磁盤上保留一份base鏡像,同時記憶體中也只需要加載一份base鏡像,這樣就可以為所有的容器服務了,而且鏡像的每一層都可以被共享,
備注:查看鏡像分層的方式可以通過 docker image inspect 命令!
拓展:所有的 Docker 鏡像都起始于一個基礎鏡像層,當進行修改或增加新的內容時,就會在當前鏡像層上,創建新的鏡像層,舉一個簡單的例子,假如基于 Ubuntu Linux 16.04 創建一個新的鏡像,這就是新鏡像的第一層;如果在該鏡像中添加 Python包,就會在基礎鏡像層之上創建第二個鏡像層;如果繼續添加一個安全補丁,就會創建第三個鏡像層,該鏡像當前已經包含 3 個鏡像層,如下圖所示(這只是一個用于演示的很簡單的例子),

在添加額外的鏡像層的同時,鏡像始終保持是當前所有鏡像的組合,理解這一點非常重要,下圖中舉了一個簡單的例子,每個鏡像層包含 3 個檔案,而鏡像包含了來自兩個鏡像層的 6 個檔案,

上圖中的鏡像層跟之前圖中的略有區別,主要目的是便于展示檔案,下圖中展示了一個稍微復雜的三層鏡像,在外部看來整個鏡像只有 6 個檔案,這是因為最上層中的檔案7 是檔案 5 的一個更新版本,這種情況下,上層鏡像層中的檔案覆寫了底層鏡像層中的檔案,這樣就使得檔案的更新版本作為一個新鏡像層添加到鏡像當中,
Docker 通過存盤引擎(新版本采用快斬訓制)的方式來實作鏡像層堆疊,并保證多鏡像層對外展示為統一的檔案系統,
Linux 上可用的存盤引擎有 AUFS、Overlay2、Device Mapper、Btrfs 以及 ZFS,顧名思義,每種存盤引擎都基于 Linux 中對應的檔案系統或者塊設備技術,并且每種存盤引擎都有其獨有的性能特點,
Docker 在 Windows 上僅支持 windowsfilter 一種存盤引擎,該引擎基于 NTFS 檔案系統之上實作了分層和 CoW[1],下圖展示了與系統顯示相同的三層鏡像,所有鏡像層堆疊并合并,對外提供統一的視圖,
![(img-GW34mpWa-1634551438154)(https://i.loli.net/2021/08/30/NVgljJnYWadeCqD.png)]https://i.loli.net/2021/08/30/NVgljJnYWadeCqD.png](https://img.uj5u.com/2021/10/19/2755071908151514.png)
特點:Docker鏡像都是只讀的,當容器啟動時,一個新的可寫層被加載到鏡像的頂部!這一層就是我們通常說的容器層,容器之下的都叫鏡像層!
Docker資料持久
容器資料卷
什么是容器資料卷,為什么要用容器資料卷?
將應用和運行的環境打包形成容器運行,運行可以伴隨著容器,但是我們對于資料的要求,是希望能夠持久化的!就好比,你安裝一個MySQL,結果你把容器刪了,就相當于刪庫跑路了,這TM也太扯了吧!所以我們希望容器之間有可能可以共享資料,Docker容器產生的資料,如果不通過docker commit 生成新的鏡像,使得資料作為鏡像的一部分保存下來,那么當容器洗掉后,資料自然也就沒有了!這樣是行不通的!為了能保存資料在Docker中我們就可以使用卷!讓資料掛載到我們本地!這樣資料就不會因為容器洗掉而丟失了!
容器資料卷作用是什么?
卷就是目錄或者檔案,存在一個或者多個容器中,由docker掛載到容器,但不屬于聯合檔案系統,因此能夠繞過 Union File System , 提供一些用于持續存盤或共享資料的特性:卷的設計目的就是資料的持久化,完全獨立于容器的生存周期,因此Docker不會在容器洗掉時洗掉其掛載的資料卷,
容器資料卷特點?
- 資料卷可在容器之間共享或重用資料
- 卷中的更改可以直接生效
- 資料卷中的更改不會包含在鏡像的更新中
- 資料卷的生命周期一直持續到沒有容器使用它為止
備注:總結一句話: 就是容器的持久化,以及容器間的繼承和資料共享!
容器資料卷如何使用?
docker run -it -v 宿主機絕對路徑目錄:容器內目錄 鏡像名
# 測驗
[root@kuangshen ~]# docker run -it -v /home/ceshi:/home centos /bin/bash
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-f8SWyTLg-1634551438155)(https://i.loli.net/2021/08/30/qnVfBJiOzKskuav.png)]
容器掛載
mysql 資料持久化的問題!
# 1、搜索鏡像
[root@kuangshen ~]# docker search mysql
NAME DESCRIPTION
STARS
mysql MySQL is a widely used, open-source
relation... 9488
# 2、拉取鏡像
[root@kuangshen ~]# docker pull mysql:5.7
5 .7: Pulling from library/mysql
54fec2fa59d0: Already exists
bcc6c6145912: Pull complete
951c3d959c9d: Pull complete
05de4d0e206e: Pull complete
319f0394ef42: Pull complete
d9185034607b: Pull complete
013a9c64dadc: Pull complete
e745b3361626: Pull complete
03145d87b451: Pull complete
3991a6b182ee: Pull complete
62335de06f7d: Pull complete
Digest:
sha256:e821ca8cc7a44d354486f30c6a193ec6b70a4eed8c8362aeede4e9b8d74b8ebb
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
# 3、啟動容器 -e 環境變數!
# 注意: mysql的資料應該不丟失!先體驗下 -v 掛載卷! 參考官方檔案
[root@kuangshen home]# docker run -d -p 3310:3306 -v
/home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e
MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
4763fa5c68c4323688102f57938fb10996a0fb902d2812349286529f9378f16c
# 4、使用本地的sqlyog連接測驗一下 3310
# 5、查看本地的 /home/mysql 目錄 [root@kuangshen data]# pwd /home/mysql/data [root@kuangshen data]# ls
.. ... . test # 可以看到我們剛剛建立的mysql資料庫在本地存盤著
# 6、洗掉mysql容器
[root@kuangshen data]# docker rm -f mysql01 # 洗掉容器,然后發現遠程連接失敗! mysql01
[root@kuangshen data]# ls
.. ... . test # 可以看到我們剛剛建立的mysql資料庫在本地存盤著
匿/具名掛載
什么是匿名和具名掛載?
# 匿名掛載
-v 容器內路徑
docker run -d -P --name nginx01 -v /etc/nginx nginx
# 匿名掛載的缺點,就是不好維護,通常使用命令 docker volume維護 docker volume ls
# 具名掛載
-v 卷名:/容器內路徑
docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx nginx
# 查看掛載的路徑
[root@kuangshen ~]# docker volume inspect nginxconfig [
{
"CreatedAt": "2020-05-13T17:23:00+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/nginxconfig/_data",
"Name": "nginxconfig",
"Options": null,
"Scope": "local"
} ]
# 怎么判斷掛載的是卷名而不是本機目錄名? 不是/開始就是卷名,是/開始就是目錄名
# 改變檔案的讀寫權限
# ro: readonly
# rw: readwrite
# 指定容器對我們掛載出來的內容的讀寫權限
docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx:ro nginx docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx:rw nginx
Docker File
DockerFile 是用來構建Docker鏡像的構建檔案,是由一些列命令和引數構成的腳本,我們在這里,先體驗下,后面我們會詳細講解 DockerFile !
測驗:
# 1、我們在宿主機 /home 目錄下新建一個 docker-test-volume檔案夾
[root@kuangshen home]# mkdir docker-test-volume
# 說明:在撰寫DockerFile檔案中使用 VOLUME 指令來給鏡像添加一個或多個資料卷
VOLUME["/dataVolumeContainer1","/dataVolumeContainer2","/dataVolumeContainer 3"]
# 出于可移植和分享的考慮,我們之前使用的 -v 主機目錄:容器目錄 這種方式不能夠直接在 DockerFile中實作,
# 由于宿主機目錄是依賴于特定宿主機的,并不能夠保證在所有宿主機上都存在這樣的特定目錄.
# 2、撰寫DockerFile檔案
[root@kuangshen docker-test-volume]# pwd /home/docker-test-volume
[root@kuangshen docker-test-volume]# vim dockerfile1 [root@kuangshen docker-test-volume]# cat dockerfile1
# volume test
FROM centos
VOLUME ["/dataVolumeContainer1","/dataVolumeContainer2"] CMD echo "-------end------"
CMD /bin/bash
# 3、build后生成鏡像,獲得一個新鏡像 kuangshen/centos
docker build -f /home/docker-test-volume/dockerfile1 -t kuangshen/centos . # 注意最后有個.
# 4、啟動容器
[root@kuangshen docker-test-volume]# docker run -it 0e97e1891a3d /bin/bash # 啟動容器
[root@f5824970eefc /]# ls -l
total 56
# 問題:通過上述步驟,容器內的卷目錄地址就已經知道了,但是對應的主機目錄地址在哪里呢?
# 5、我們在資料卷中新建一個檔案
[root@f5824970eefc dataVolumeContainer1]# pwd /dataVolumeContainer1
[root@f5824970eefc dataVolumeContainer1]# touch container.txt [root@f5824970eefc dataVolumeContainer1]# ls -l
total 0
-rw-r--r-- 1 root root 0 May 11 11:58 container.txt
# 6、查看下這個容器的資訊
[root@kuangshen ~]# docker inspect 0e97e1891a3d # 查看輸出的Volumes
"Volumes": {
"/dataVolumeContainer1": {},
"/dataVolumeContainer2": {}
},
# 7、這個卷在主機對應的默認位置
# 注意:如果訪問出現了 cannot open directory: Permission denied 解決辦法:在掛載目錄后多加一個 --privileged=true引數即可
資料卷容器
有人會問資料卷容器和容器資料卷有什么區別?
? 它們都是一種同步、持久化技術,容器資料卷是為了防止洗掉容器的時候資料丟失,構建起鏡像和外部檔案系統同步機制;資料卷容器是其他的容器通過掛載這個父容器實作資料共享,掛載資料卷的容器,是容器之間資料共享同步機制(類似于單專案集群思想),

資料卷容器如何使用?
我們使用上一步的鏡像:kuangshen/centos 為模板,運行容器 docker01,docker02,docker03,他們都會具有容器卷,我們來測試下,容器間傳遞共享
docker run -it - -name parentContainer 鏡像名 #建立父容器
#語法:--volumes-from
docker run -it - -name sonContainer1 --volumes -from parentContainer 鏡像名
docker run -it - -name sonContainer2 --volumes -from parentContainer 鏡像名
結論:容器之間配置資訊的傳遞,資料卷的生命周期一直持續到沒有容器使用它為止,存盤在本機的檔案則會一直保留!
DockerFile
DockerFile基礎
大家想想,Nginx,tomcat,mysql 這些鏡像都是哪里來的?官方能寫,我們不能寫嗎?如何實作自己的docker鏡像,么就需要用到DockerFile
-
微服務單體springboot應用打包成鏡像(包含資料庫、APP、訊息佇列…)
-
流程:開發應用=>DockerFile=>打包為鏡像=>上傳到倉庫(私有倉庫,公有倉庫)=> 下載鏡像 => 啟動
什么是DockerFile?
DockerFile是用來構建Docker鏡像的構建檔案,是由一系列命令和引數構成的腳本,
如何實作一個dockerFile?
基礎知識:

FROM # 基礎鏡像,當前新鏡像是基于哪個鏡像的 MAINTAINER # 鏡像維護者的姓名混合郵箱地址
RUN # 容器構建時需要運行的命令
EXPOSE # 當前容器對外保留出的埠
WORKDIR # 指定在創建容器后,終端默認登錄的進來作業目錄,一個落腳點
ENV # 用來在構建鏡像程序中設定環境變數
ADD # 將宿主機目錄下的檔案拷貝進鏡像且ADD命令會自動處理URL和解壓tar壓縮包 COPY # 類似ADD,拷貝檔案和目錄到鏡像中!
VOLUME # 容器資料卷,用于資料保存和持久化作業
CMD # 指定一個容器啟動時要運行的命令,dockerFile中可以有多個CMD指令,但只有最 后一個生效!
ENTRYPOINT # 指定一個容器啟動時要運行的命令!和CMD一樣
ONBUILD # 當構建一個被繼承的DockerFile時運行命令,父鏡像在被子鏡像繼承后,父鏡像的 ONBUILD被觸發
DockerFile測驗
建構步驟:撰寫DockerFile檔案>docker build 構建鏡像>docker run
例子地址:https://hub.docker.com/_/centos
創建app.py
#ipython
#ipython os
#mkdir python_app
#cd python_app
#vim app.py:
from flask import Flask #from模塊呼叫
import socket #為了獲取主機名稱用
import os #獲取環境變數用的
app = Flask(__name__)
@app.route('/')
def hello():
html = "Hello {name} Hostname: {hostname} This is Dockerfile Demo"
return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname())
if __name__ == "__main__": #主函式
app.run(host='0.0.0.0', port=80) #監控本地所有的網卡、監控80埠
創建requirements.txt
Flask
創建Dockerfile
FROM python:3.7-alpine
WORKDIR /app
ADD . /app
RUN pip install --trusted-host pypi.python.org -r requirements.txt
# 使用 pip 命令安裝這個應用所需要的依賴
EXPOSE 80
# 允許外界訪問容器的 80 埠
ENV NAME World
# 設定環境變數
CMD ["python", "app.py"]
DockerFile拓展
除上述的功能點以外Dockerfile還提供了HEALTHCHECK(狀態服務監控)、ENV/ARG(環境配置)、ENTRYPOINT(入口指令)等功能,有興趣的小伙伴可以去研究一下,
Docker Compose
什么是Docker Compose?
? Compose 是用于定義和運行多容器 Docker 應用程式的工具,通過 Compose,您可以使用 **YML **檔案來配置應用程式需要的所有服務,然后,使用一個命令,就可以從 YML 檔案配置中創建并啟動所有服務,
Docker Compose安裝
安裝地址:https://docs.docker.com/compose/install/
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
#備注:要安裝其他版本的 Compose,請替換 1.24.1,
# 將可執行權限應用于二進制檔案:
sudo chmod +x /usr/local/bin/docker-compose
# 創建軟鏈:
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
# 測驗是否安裝成功:
docker-compose --version
#輸出:cker-compose version 1.24.1, build 4667896b
# 卸載
sudo rm /usr/local/bin/docker-compose
pip uninstall docker-compose
Docker Compose測驗
mkdir composetest
cd composetest
建一個py.app檔案
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
@app.route('/')
def hello():
count = get_hit_count()
return 'Hello World! I have been seen {} times.\n'.format(count)
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
創建一個txt檔案requirements.txt
flask
redis
創建一個Dockerfile
FROM python:3.4-alpine
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
創建 docker-compose.yml
# yaml 配置
version: '3'
services:
web:
build: .
ports:
- "8848:8848"
redis:
image: "redis:alpine"
專案構建
# 啟動應用程式:
docker-compose up
#后臺執行該服務可以加上 -d 引數:
docker-compose up -d
Docker Compose拓展
除了上面常見的配置,Docker Compose yaml 配置還提供了 endpoint_mode(集群模式vip和輪詢機制dnsrr)、healthcheck、logging、network_mode、restart、secrets(存盤敏感資料)、devices、dns、env_file、extra_hosts(主機映射)…等等,大家有興趣的可以去研究一下,
Docker 網路講解

Docker容器互聯
Docker0(IP)

問題:什么是Docker0?
? Docker啟動的時候會在主機上自動創建一個docker0網橋,實際上是一個Linux網橋,所有容器的啟動如果在docker run的時候沒有指定網路模式的情況下都會掛載到docker0網橋上,這樣容器就可以和主機甚至是其他容器之間通訊了,
docker network ls # Docker網路(bridge:橋接模式 host:主機模式 none:無網路模式)
docker rm -f $(docker ps -a -q) # 洗掉所有容器
docker rmi -f $(docker images -qa) # 洗掉全部鏡像
問題:Docker 是如何處理容器網路訪問的?
每一個安裝了Docker的linux主機都有一個docker0的虛擬網卡,這是個橋接網卡,使用了veth-pair技術!
小結:
Docker使用Linux橋接,在宿主機虛擬一個Docker容器網橋(docker0),Docker啟動一個容器時會根據Docker網橋的網段分配給容器一個IP地址,稱為Container-IP,同時Docker網橋是每個容器的默認網關,因為在同一宿主機內的容器都接入同一個網橋,這樣容器之間就能夠通過容器的Container-IP直接通信,
Docker容器網路就很好的利用了Linux虛擬網路技術,在本地主機和容器內分別創建一個虛擬介面,并讓他們彼此聯通(這樣一對介面叫veth pair);Docker中的網路介面默認都是虛擬的介面,虛擬介面的優勢就是轉發效率極高(因為Linux是在內核中進行資料的復制來實作虛擬介面之間的資料轉發,無需通過外部的網路設備交換),對于本地系統和容器系統來說,虛擬介面跟一個正常的以太網卡相比并沒有區別,只是他的速度快很多,
Docker–Link(容器名)
??思考一個場景,我們撰寫一個微服務,資料庫連接地址原來是使用ip的,如果ip變化就不行了,那我們能不能使用服務名訪問呢?jdbc:mysql://mysql:3306,這樣的話哪怕mysql重啟,我們也不需要修改配置了!docker提供了 --link的操作!
docker run --name mysql --restart=always -d -e MYSQL_ROOT_PASSWORD=123456 mysql:5.6
docker run -d --name 接收容器名(#一般是tomcat) --link 源容器(被連接容器)(#一般是mysql) --restart=always 源容器鏡像名
docker run -d -p 8080:8080 --name tomcat --link mysql --restart=always -v /data/tomcat/webapps:/usr/local/tomcat/webapps tomcat
備注:–link早都過時了,我們不推薦使用!我們可以使用自定義網路的方式
自定義網路

# 命令
[root@kuangshen ~]# docker network inspect 4eb2182ac4b2 [
{
"Name": "bridge",
"Id":
"4eb2182ac4b23487e1eb6e06df56c71ab6f0adc7ccc0962b4747d0eed5ad6690",
"Created": "2020-05-11T15:44:20.131441544+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
// 默認docker0是管理這個子網范圍內的,0~16,也就是 255*255,去掉0個255,我們有65534可以分配的ip
// docker0網路默認可以支持創建6萬多個容器ip不重復
] },
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"a3a4a17a2b707766ad4f2bb967ce1d94f658cd4cccef3bb8707395cdc71fa1e7": {
"Name": "tomcat03",
"EndpointID":
"5fe62d0be3a1343aa74f6bb77885d3657b191210cafad200e5054e1bdfe56be9",
"MacAddress": "02:42:ac:12:00:04",
"IPv4Address": "172.18.0.4/16",
"IPv6Address": ""
},
"b80da266a3ad85fcc874c5f0d3c897246ebc40533cb745bb24180237cc3167b1": {
"Name": "tomcat02",
"EndpointID":
"6232cac0c4e7fed30c9fa5eebc9238f9fc44f548f257344b5440d6d486825256",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": ""
},
"f38239e2b405bccf8c93bd1052f336f661033b9b27ef9b3f99a018c108e06f87": {
"Name": "tomcat01",
"EndpointID":
"31dc174b8f3f15f217acdc3ac7e8a235a03d59438f863706c0143b4426772c5e",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
} },
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
# 默認我們不配置網路,也就相當于默認值 --net bridge 使用的docker0
docker run -d -P --name tomcat01 --net bridge tomcat
# docker0網路的特點
1.它是默認的
2.域名訪問不通
3.--link 域名通了,但是刪了又不行
備注:聊了這么多,我們現在應該可以深刻理解docker的網路了!
實戰:部署Redis集群
# 創建網卡
docker network create redis --subnet 172.38.0.0/16
# 通過腳本創建六個redis配置
for port in $(seq 1 6); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.1${port} redis:5.0.9-alpine3.11 redis-server
/etc/redis/redis.conf; \
# 啟動6個容器
docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
-v /mydata/redis/node-1/data:/data \
-v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6376:6379 -p 16376:16379 --name redis-6 \
-v /mydata/redis/node-6/data:/data \
-v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.16 redis:5.0.9-alpine3.11 redis-server
/etc/redis/redis.conf
# 進入一個redis,注意這里是 sh命令 docker exec -it redis-1 /bin/sh
# 創建集群
redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 -- cluster-replicas 1
# 連接集群 redis-cli -c
# 查看集群資訊 cluster info
# 查看節點 cluster nodes
# set a b
# 停止到存值的容器
# 然后再次get a,發現依舊可以獲取值 # 查看節點,發現高可用完全沒問題
文章參考
[1]Docker官網.https://www.docker.com/[EB/OL].
[2]菜鳥Docker.https://www.runoob.com/docker/docker-tutorial.html[EB/OL].
[3]遇見狂神說.Docker最新超詳細版教程通俗易懂[EB/OL].2020-05-16/至今.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/323292.html
標籤:其他
