docker 基礎進階
Docker為什麼出現?#
- 開發和運維兩套環境,而環境配置十分麻煩。
如在Windows上開發,要釋出到Linux上執行。Docker給以上問題提出瞭解決方案:
Java --- Jar(環境)---打包專案帶上環境(映象)---Docker倉庫(應用商店)---下載映象---直接執行 - Docker的思想來自於集裝箱,核心思想:隔離。
即將應用打包裝箱,每個箱子是互相隔離的,可以將伺服器利用到極致。
虛擬機器 | Docker |
---|---|
linux centos原生映象(一個電腦) | 隔離映象(最核心的環境 +jdk +mysql等) |
需要開啟多個虛擬機器 | 執行映象就可以了 |
幾GB | 幾MB |
官方文件#
倉庫地址#
Docker能做什麼?#
傳統虛擬機器與Docker對比#
Docker的優點#
- 不模擬完整的作業系統,系統核心(kernel)非常小,更少的抽象層(GuestOS:如Centos)
- 容器內的應用直接執行在宿主機的核心,容器本身沒有自己的核心,也沒有虛擬硬體。
- 每個容器相互隔離,內部都有屬於自己的檔案系統,互不影響。
Docker實現DevOps(開發、運維)#
- 應用更快速的交付和部署
打包映象釋出測試,一鍵執行;不再需要寫大量幫助文件,安裝程式 - 更便捷的升級和擴縮容?
部署應用就和搭積木一樣 - 更簡單的系統運維
開發和測試的環境高度一致 - 更高效的計算資源利用
核心級別的虛擬化,可以在一個物理機上執行很多的容器例項,伺服器效能可以被壓榨到極致。
Docker的基本組成#
- 映象(image):映象是一種輕量級、可執行的獨立軟體包,用來打包軟體執行環境和基於執行環境開發的軟體。它包含執行某個軟體所需的所有內容,包括程式碼、執行時、庫、環境變數和配置檔案。相當於一個模板,通過這個模板來建立容器服務,可以通過一個映象建立多個容器。
- 容器(container):獨立執行一個或一組應用/基本命令有:啟動,停止,刪除等/可理解為一個簡單的linux系統。
- 倉庫(repository):存放映象的地方(公有/私有)
Docker執行原理#
Docker是一個Client-Server結構的系統,以守護程序執行在主機上。通過Socket從客戶端進行訪問。
Docker的常用命令#
幫助命令#
docker --help # 幫助資訊
docker info # 系統資訊,包括映象和容器的數量
幫助文件地址:https://docs.docker.com/engine/reference/
映象命令#
docker search 映象名 # 搜尋映象
docker pull 映象名 # 下載映象
Docker採用聯合檔案系統,不同映象的相同檔案無需再次下載:
docker rmi 映象名/id 刪除映象
容器命令#
docker run [options] 映象名/id [command] # 建立容器並啟動:
[options]:
--name=容器名 # 命名容器以區分不同容器
-d # 在後臺執行容器(必須有一個前臺程序,否則程序會自動關閉)
-it # 使用互動方式執行,進入容器檢視內容
-p 主機埠:容器埠 # 暴露指定容器埠
-P # 暴露容器所有埠
[command]:
/bin/bash # 控制檯
Exit # 從容器中退回主機
CTRL+Q+P # 容器不停止退出
docker ps # 顯示當前執行的容器
-a # 帶出歷史執行過的容器
docker rm 容器名/id # 刪除指定容器
docker rm &(docker ps -aq) # 刪除全部容器
其他命令#
docker start/restart/stop/kill 容器名/id
docker logs -tf --tail 顯示的日誌條數 容器名/id # 檢視日誌
docker top 容器名/id # 檢視容器中的程序資訊
docker inspect 容器名/id # 檢視映象的元資料
docker exec -it 容器名/id /bin/bash # 通常容器以後臺方式執行,需要進入其中修改配置:進入容器後開啟一個新終端
docker attach 容器名/id # 進入容器正在執行的終端
docker cp 容器名/id:容器內路徑 主機檔案路徑 # 從容器內拷貝檔案到主機上
Docker映象詳解#
UnionFS(聯合檔案系統)#
- 聯合檔案系統(UnionFS)是一種分層、輕量級並且高效能的檔案系統,它支援對檔案系統的修改作為一次提交來一層層的疊加,同時可以將不同目錄掛載到同一個虛擬檔案系統下。聯合檔案系統是 Docker 映象的基礎。映象可以通過分層來進行繼承,基於基礎映象(沒有父映象),可以製作各種具體的應用映象。
- 特性:一次同時載入多個檔案系統,但從外面看起來只能看到一個檔案系統。聯合載入會把各層檔案系統疊加起來,這樣最終的檔案系統會包含所有底層的檔案和目錄。
映象載入原理#
Docker的映象實際由一層一層的檔案系統組成:
- bootfs(boot file system)主要包含bootloader和kernel。bootloader主要是引導載入kernel,完成後整個核心就都在記憶體中了。此時記憶體的使用權已由bootfs轉交給核心,系統解除安裝bootfs。可以被不同的Linux發行版公用。
- rootfs(root file system),包含典型Linux系統中的/dev,/proc,/bin,/etc等標準目錄和檔案。rootfs就是各種不同作業系統發行版(Ubuntu,Centos等)。因為底層直接用Host的kernel,rootfs只包含最基本的命令,工具和程式就可以了。
- 分層理解
所有的Docker映象都起始於一個基礎映象層,當進行修改或增加新的內容時,就會在當前映象層之上,建立新的容器層。
容器在啟動時會在映象最外層上建立一層可讀寫的容器層(R/W),而映象層是隻讀的(R/O)。
docker commit -m="描述資訊" -a="作者" 容器id 目標映象名:[tag] # 編輯容器後提交容器成為一個新映象
容器資料卷#
什麼是容器資料卷?#
為了實現資料持久化,使容器之間可以共享資料。可以將容器內的目錄,掛載到宿主機上或其他容器內,實現同步和共享的操作。即使將容器刪除,掛載到本地的資料卷也不會丟失。
使用容器資料卷#
使用命令:
dokcer run -it -v 主機內目錄:容器內目錄 映象名/id
將容器內目錄掛載到主機內目錄上,通過docker inspect命令檢視該容器即可以看到掛載資訊:
建立掛載關係後,只要使用命令在主機內新建一個檔案:
touch /home/mountdir/test.txt
就會在容器內的掛載目錄下發現相同的檔案(test.txt),從而實現了容器和主機的檔案同步和共享:
匿名掛載#
docker run -d -v 容器內目錄 映象名/id # 匿名掛載
匿名掛載後,使用docker volume ls命令檢視所有掛載的卷:
每一個VOLUME NAME對應一個掛載的卷,由於掛載時未指定主機目錄,因此無法直接找到目錄。
具名掛載#
docker run -d -v 卷名:容器內目錄 映象名/id # 具名掛載
可以發現掛載的卷:volume01,並通過docker volume inspect 卷名 命令找到主機內目錄:
所有docker容器內的卷,在未指定主機內目錄時,都在:/var/lib/docker/volumes/卷名/_data 下,可通過具名掛載可以方便的找到卷,因此廣泛使用這種方式進行掛載。
資料卷容器#
docker run -it --name container02 --volumes from container01 映象名/id # 將兩個容器進行掛載
DockerFile#
Dockerfile是用來構建docker映象的檔案
構建步驟:#
編寫一個dockerfile檔案,隨後執行命令:
docker build -f 檔案路徑 -t 標籤 . # 檔名為Dockerfile時可省略且最後的.不要忽略
docker run # 執行映象
docker push # 釋出映象
dockerfile命令#
命令 | 效果 |
---|---|
FROM | 基礎映象:Centos/Ubuntu |
MAINTAINER | 映象作者+郵箱 |
RUN | 映象構建的時候需要執行的命令 |
ADD | 為映象新增內容(壓縮包) |
WORKDIR | 映象工作目錄(進入容器時的目錄) |
VOLUME | 掛載的目錄 |
EXPOSE | 暴露埠配置 |
CMD/ENTRYPOINT | 指定這個容器啟動時要執行的命令(CMD替代先前命令,ENTRYPOINT在先前命令後追加) |
COPY | 類似於ADD,將檔案拷貝到映象中 |
ENV | 構建時設定環境變數 |
構建過程#
- 每個保留關鍵字(指令)都必須是大寫字母
- 從上到下順序執行
- "#" 表示註釋
- 每一個指令都會建立提交一個新的映象層並提交
構建例項#
Docker網路#
理解Doker0#
通過命令ip addr檢視本地ip地址,我們發現除了本機迴環地址和埃裡遠的內網地址外,還多了一個網絡卡:Docker0,這是Docker服務啟動後自動生成的。
而如果進入一個正在後臺執行的tomcat容器,同樣使用ip addr命令,發現容器得到了一個新的網路:12: eth@if13,ip地址:172.17.0.2。這是Docker在容器啟動時為其分配的。
思考一個問題:此時我們的linux主機可以ping通容器內部(172.17.0.2)嗎?(注意與容器暴露埠相區分)
- linux可以ping通docker容器內部,因為docker0的ip地址為172.17.0.1,容器為172.17.0.2。
- 原理:我們每啟動一個docker容器,docker就會給容器分配一個預設的可用ip,我們只要安裝了docker,就會有一個網絡卡docker0(bridge)。網絡卡採用橋接模式,並使用veth-pair技術(veth-pair就是一堆虛擬裝置介面,成對出現,一段連著協議,一段彼此相連,充當一個橋樑。)。
- 這時我們退出容器,回到主機再次觀察主機的ip地址:
我們驚奇地發現了一個新網路13: vethda1df4b@if12,對應容器內網路地址的12: eth@if13。 - 容器和容器之間是可以互相ping通的:容器1→Docker0→容器2
docker中的所有網路介面都是虛擬的 ,轉發效率高。刪除容器後,對應的網橋也隨之刪除。
--link#
若編寫一個微服務並連線資料庫,如果資料庫ip改變,如何根據容器名而不是ip訪問容器?顯然,直接使用容器名是無法ping通容器內部的:
這時我們可以在容器啟動命令中加入一個選項:--link,使得我們可以根據容器名來訪問容器。
docker run -d -P --link 容器名/id 映象名/id
然而反向就不可以ping通,這是因為--link的本質是把需要連線的容器名/id寫入啟動容器的配置檔案中,即增加了一個ip和容器名/id的對映:
目前已經不建議使用這種方式。
自定義網路#
我們使用命令:
docker network ls # 檢視所有的docker網路
- bridge:橋接(docker預設)/
- none:不配置網路 /
- host:和宿主機共享網路
docker run 命令預設帶有一個引數--net bridge,此處的bridge指的就是docker0。如果我們不想使用docker0,那如何建立一個新的網路呢?
docker network create --driver 網路模式 --subnet 子網ip --gateway 閘道器 網路名
我們不僅在docker network ls命令下發現了這個新建立的網路newnet,還可以使用docker network inspect命令檢視其詳細資訊,包括了我們建立時定義的子網ip和閘道器:
只要兩個容器啟動時都通過 --net,選用了同一個已建立的網路,不同容器間即可通過ip地址或容器名/id連通:
網路連通#
對於建立在不同網路下(docker0, newnet)的兩個容器tomcat01和tomcat02,他們的網段不同,因此是無法彼此ping通容器內部的:
這時我們需要通過docker network connect命令打通容器與網路之間的連線:
docker network connect 網路名 容器名/id
這個功能類似於將一個容器賦予多個ip地址,同樣可以用docker network inspect命令檢視網路連通後,該網路的變化:
原本newnet網路中只含有tomcat02,現在增加了tomcat01,因此可以連通。
Docker
DockerFile build run 手動操作,單個容器
微服務,100個微服務,依賴關係
Docker Compose來輕鬆高效的管理容器,定義執行多個容器
官方介紹
定義、執行多個容器
YAML file配置檔案
single command,命令有哪些?
Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration. To learn more about all the features of Compose, see the list of features.
Compose works in all environments: production, staging, development, testing, as well as CI workflows. You can learn more about each case in Common Use Cases.
Using Compose is basically a three-step process:
- Define your app’s environment with a Dockerfile so it can be reproduced anywhere.
Dockerfile保證我們的專案在任何地方都可以執行 - Define the services that make up your app in docker-compose.yml so they can be run together in an isolated environment.
- services什麼是服務
- docker-compose.yml這個檔案怎麼寫
-
Run docker compose up and the Docker compose command starts and runs your entire app. You can alternatively run docker-compose up using the docker-compose binary.
啟動專案
作用:批量容器編排
我自己的理解
Compose是Docker官方的開源專案,需要安裝
Dockerfile
讓程式在任何地方執行,web服務,redis、mysql、nginx…多個容器
Compose
version: "3.9" # optional since v1.27.0
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
- logvolume01:/var/log
links:
- redis
redis:
image: redis
volumes:
logvolume01: {}
docker compose up 100個服務
Compose:重要的概念。
- 服務services,容器,應用(web、redis、mysql)
- 專案project,一組關聯的容器。
2 ) 安裝
- 下載
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 這個可能快點
curl -L https://get.daocloud.io/docker/compose/releases/download/1.29.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
- 授權
sudo chmod +x /usr/local/bin/docker-compose
3 ) 體驗
python應用,計數器,redis
1、應用app.py
- 為專案建立資料夾
mkdir composetest
cd composetest
- 建立
app.py
檔案
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)
- 建立`requirements.txt`檔案
flask
redis
2、Dockerfile應用打包為映象
建立Dockerfile
檔案
# syntax=docker/dockerfile:1
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]
3、Docker-compose yaml檔案(定義整個服務於,需要的環境,web、redis)
version: "3.9"
services:
web:
build: .
ports:
- "5000:5000"
redis:
image: "redis:alpine"
4、啟動compose
docker-compose up
docker-compose up的執行流程
1、建立網路
2、執行Docker-compose yaml
3、啟動服務
Creating composetest_web_1 … done
Creating composetest_redis_1 … done
docker images
自動的預設規則
1、檔名 composetest
2、服務
預設的服務名 檔名_num
多個伺服器,叢集 A B_num 副本數量
服務redis服務=>4個副本
叢集狀態,服務都不可能只有一個執行例項。彈性、10 HA 高併發
3、網路規則
10個服務=>專案(專案中的內容都在同一個網路下,域名訪問)
如果在同一個網路下,我們可以通過域名進行訪問
停止命令
docker-compose down
Ctrl+C
docker-compose
以前都是單個docker run啟動容器
docker-compose通過docker-compose編寫yaml配置檔案、可以通過compose一鍵啟動所有服務,停止
Docker小結:
1、Docker映象,run=>容器
2、DockerFile構建映象(服務打包)
3、docker-compose啟動專案(編排、多個微服務/環境)
4、Docker網路
4 ) yaml 規則
docker-compose.yaml 核心
# 3層
version: '' # 版本
services: # 服務
服務1: web
# 服務配置
images
build
network
......
服務2: redis
.....
服務3: mysql
.....
# 其他配置 網路/卷 全域性規則
volumes:
networks:
configs
5 ) 實戰
- 使用Compose一鍵部署WP部落格
- 自己編寫微服務上線
開源專案(部落格)
docker-compose up -d #後臺啟動
實戰
Docker Swarm(購買伺服器)
點 建立例項
按量付費:用時花錢,不用不收錢
分組可以不設定
4臺機器安裝docker
工作模式
搭建叢集
生成令牌在任何一個manager節點上就可以
Raft協議
體會
命令只能在manager上執行
雖然是在docker-1機器上建立的,但1、2、4上都沒有這個docker程序
跑到了3上,docker-3也是manager節點
動態更新nginx成3個副本,1上沒有,2、3、4都有nginx。但用1的ip訪問也能訪問到nginx
如果開10個時,四個節點上分別跑3、3、2、2個nginx容器。
同樣的命令也可以再設定成只有1個副本
k8s更難,功能更多。swarm相當於簡單版的k8s
概念總結
docker network inspect ingress
Overlay可使多個相互;ping不同的機器聯通並變成一個整體
Docker Stack
Docker Secret
k8s中也有這個概念,學k8s的時候再說
Docker Config
超過10臺用k8s不用swarm
筆記參考:https://blog.csdn.net/czj981014/article/details/116766286
ter)
超過10臺用k8s不用swarm