容器是時下的人們技術,公司也要求員工對此進行學習和應用。
前段時間看了B站上的尚硅谷的視頻課,在此記錄一下Docker學習的一些筆記,供大家參考,請幫忙斧正。侵刪。
建議先適當學習一些Linux的常用命令和相關背景,瞭解Maven/Git的一些相關知識。
目錄
0. 學習視頻
視頻課 https://www.bilibili.com/video/av47715282?from=search&seid=2009861769979326156 8h
1. Docker簡介
1.1 Docker爲什麼會出現?
一款產品從開發到上線,從OS、到運行環境,再到應用配置。作爲開發+運維之間的寫作我們需要關心很多東西。這也是很多互聯網公司都不得不面對的問題,特別是各種版本的迭代之後,不同版本環境的兼容,對運維人員都是考驗。
Docker之所以發展如此迅速,也是因爲它給出了一個標準化的解決方案。
原始情況: 開發和運維——環境和配置
==》進階
環境配置如此麻煩,換一臺機器,就要從來一次,費力費時。很多人想到,能不能從根本上解決問題,軟件可以帶環境安裝?也就是說,安裝的時候,把原始環境一模一樣的複製過來,開發人員利用Docker可以消除協作編碼時“在我的機器上可以正常工作,在你的機器上不行”的問題。
Docker三要素:鏡像、容器(集裝箱)、倉庫
之前在服務器配置一個應用的運行環境,要安裝各種軟件,安裝起來麻煩不說還不能實現跨平臺。加入我們再windows上安裝的這些環境,到了Linux上又得重新裝,況且就算不跨操作系統,換另一臺同樣操作系統的服務器要移植應用也是非常麻煩的。
傳統上認爲,軟件編碼開發測試結束後,所產出的成果就是程序或能夠編譯執行的二進制節碼等(java爲例),而爲了讓這些程序可以順利的執行,開發團隊也得準備完整的部署文件,讓運維團隊得以部署應用程式。開發需要清楚的告訴運維部署團隊,用的全部配置文件+所有軟件環境。不過,即使如此仍然常常發生部署失敗的狀況。Docker鏡像的設計,使得Docker得以打破過去【程序即應用】的觀念,通過鏡像(images)將作業系統核心除外,運作應用程式所需要的系統環境,自上而下的打包,達到應用程式跨平臺的無縫接軌運作。
1.2 Docker的理念
Docker是基於Go語言實現的雲開源項目。
Docker的主要目標是“Build,Ship and run any app anywhere”。也就是通過對應用組件的封裝、分發、部署、運行等生命週期的管理,使用戶的APP(可以是一個WEB應用或數據庫應用等)及其運行環境能夠做到“一次封裝、到處運行”
Linux容器技術的出現就解決了這樣一個問題,而Docker就是在它的基礎上發展過來的。將應用那個程序運行在Docker容器上面,而Docker容器在任何OS上都是一致的,這就實現了跨平臺、跨服務器。只需要一次配置環境,換到別的機子上就可以一鍵部署好,大大簡化了操作。
1.3 總結起來一句話:
解決了運行環境和配置問題的軟件容器,方便做持續集成並有助於整體發佈的容器虛擬化技術。
1.4 Docker能夠幹什麼??
- 之前的虛擬機(virtual machine)技術:就是帶環境安裝的一種解決方案
- 它可以在OS裏面運行另一種OS,比如Windows系統裏面運行Linux系統。應用程序對此毫無感知。因爲虛擬機看上去和真實系統一模一樣,而對於底層系統來說,虛擬機就是一個普通文件,不需要了就刪掉,對其他部分毫無影響,這類虛擬機完美的運行了另一套系統,能夠使應用程序,操作系統和硬件之間三者的邏輯不變。
- 缺點:資源佔用多,啓動慢
- Docker容器技術
- 由於前面虛擬機存在這些缺點,Linux發展出了另一種虛擬化技術:Linux容器(Linux Containers,縮寫爲LXC)。
- LXC容器不是模擬一個完整的操作系統,而是對進程進行隔離。有了容器,就可以將軟件運行所需的所有資源打包到一個隔離的容器中。容器與虛擬機不同,不需要捆綁一整套操作系統,只需要軟件工作所需的庫資源和設置。系統也因此變得更高效輕量並保證部署在任何環境中的軟件都能始終如一的運行。
比較Docker和傳統虛擬化方式的不同:
- 傳統虛擬機技術是虛擬出一套硬件之後,在其上運行一個完整的操作系統,在該系統上再運行所需應用進程。
- 而容器內的應用進程直接運行於宿主的內核,容器內沒有自己的內核,而且也沒有硬件虛擬。因此容器要比傳統的虛擬機更爲輕便。
- 每個容器之間相互隔離,每個容器有自己的文件系統,容器之間進程不會互相影響,能夠區分計算資源。
- 開發/運維(DevOps)
- 一次構建、隨處運行
- 更高效的計算資源利用
- 更簡單的系統運維
- 更便捷的升級和擴容縮
- 更快速的應用交付和部署
- 一次構建、隨處運行
- 企業級:
2 Docker安裝
2.1 前提
Cent OS安裝:CentOS 6.5以上
2.2 Docker基本組成
2.2.1 架構圖
2.2.2 三大要素
Docker的三大要素是:
- 1. 鏡像images - 就是一個只讀的模板。鏡像可以用來創建Docker 容器,一個鏡像可以創建很多容器。
- 2. 容器 container -Docker利用容器獨立運行的一個或一組應用。 容器是鏡像創建的運行實例。
它可以啓動、開始、停止、刪除、每個容器都是相互隔離的,保證安全的平臺。可以把
- 容器看做一個簡易版的Linux運行環境(包括root用戶權限、進程空間、用戶控件和網絡空間等)和運行其中的應用程序。
- 容器的定義和鏡像幾乎一模一樣,也是一堆層的統一視角,唯一區別在於容器的最上面那一層是可讀可寫的。
- 3. 倉庫repository:用來存放鏡像的場所
- Repository和倉庫註冊服務器(registry)是有區別的。倉庫註冊服務器上往往存放着多個倉庫,每個倉庫中由包含了多個鏡像,每個鏡像又有不同的標籤(tag)
- 倉庫分爲公開倉庫(public)和私有倉庫(private)兩種形式。
- 最大的公開倉庫是Docker Hub,存放了數量龐大的鏡像供用戶下載。國內的公開倉庫包括阿里雲、網易雲等。
要正確的理解倉庫,鏡像,和容器的這幾個概念:
Docker 本身是一個容器運行載體或稱之爲管理引擎。我們把應用程序和配置依賴打包好形成一個可交付的運行環境,這個打包好的運行環境就是image鏡像文件。只有通過這個鏡像文件才能生存Docker容器。image文件可以看做容器的模板。Docker根據image文件生成容器的實例。同一個image文件,可以生成多個同時運行的容器實例。
- image文件生產的容器實例,本身也是一個文件,稱爲鏡像文件
- 一個容器運行一種服務,當我們需要的時候,就可以通過docker客戶端創建一個對應的運行實例,也就是我們的容器
- 至於倉庫,就是放了一對鏡像的地方,我們可以把鏡像發佈到倉庫中,需要的時候從倉庫中拉下來就可以了。
2.2.3 Docker安裝
- 阿里雲鏡像加速
- 是什麼: https://dev.aliyun.com/search.html
- 註冊一個屬於自己的阿里雲賬戶
- 獲得加速器地址鏈接
- 配置docker後臺加速器
- 重新啓動docker daemon
- 網易鏡像加速
- HelloWorld實例
$ docker run hello-world
docker run做了什麼?
3 Docker底層運行原理
Docker是一個Client-Server結構的系統,Docker守護進程運行的主機上,然後通過Socket連接從客戶端訪問,守護進程從客戶端接受命令並管理運行在主機上的容器。容器,是一個運行時環境,就是我們前面說到的集裝箱。
爲什麼Docker比VM快?
- Docker有着比虛擬機更少的抽象層。由於docker不需要hypervisor實現硬件資源虛擬化,運行在docker容器上的程序直接使用的都是實際物理機的硬件資源。因此在CPU、內存利用率上docker將會在效率上更有明顯優勢。
- DOcker利用的是宿主機的內核,而不需要Guest OS。因此,當新建一個容器時,docker不需要和虛擬機一樣重新加載一個操作系統內核。因而避免引尋、加載操作系統內核翻個比較費時費資源的過程,當新建一個虛擬機時,虛擬機軟件需要加載GuestOS,這個新建過程是分鐘級別的。而Docker 由於直接利用你宿主機的操作系統,則省略了這個過程,因此新建一個docker容器只需要幾秒鐘。
4 Docker常用命令
Docker 鯨魚背上有集裝箱。
藍色的大海里面 -- 宿主機系統windows10
鯨魚 -- docker
集裝箱 -- 容器實例 -- from鏡像模板
4.1 幫助命令
docker --version
docker --info
docker --help
4.2 鏡像命令
- docker images: 列出本地倉庫的鏡像模板
options:
-a:列出本地所有鏡像(含中間映像層) -q: only show image id --digests: 顯示鏡像的摘要信息 --no-trunc:顯示完整的鏡像信息 |
結果:
tag:標記了鏡像的標籤。同一個倉庫可以有多個tag,代表這個倉庫源的不同版本。我們使用"repository:tag"來定義不同的鏡像。 repository: 倉庫的名稱 imageid:鏡像ID created:鏡像創建時間 size:鏡像大小 |
- docker search xxx鏡像名字: Search the Docker Hub for images
Options:
--no-trunc: 顯示完整的鏡像信息 -s: 列出收藏數不小於指定值的鏡像 --automated: 只列出automated build類型的鏡像 |
- docker pull XXX鏡像名字: 下載鏡像
- docker rmi xxx鏡像名字ID
- 刪除鏡像: docker rmi -f 鏡像ID/鏡像名字
- 刪除單個鏡像: docker rmi -f 鏡像id
- 刪除多個鏡像: docker rmi -f 鏡像名字1:tag 鏡像名字2:tagdo
- 刪除全部: docker rmi -f $(docker images -qa)
4.3 Docker容器命令
4.3.1 基本命令
有鏡像才能create容器,這是根本前提。現在我們下載一個centos的鏡像延時 --docker pull centos
- 新建並啓動容器: docker run[OPTIONS] IMAGE[COMMOND] [arg…]
注意:啓動交互式窗口:
docker run -it imagename/id
- 列出當前所有正在運行的容器 docker ps (鯨魚背上有哪些)
- 退出容器:兩種方式
- exit:容器停止退出
- ctrl+P+Q:容器不停止、退出
- 啓動容器:docker start [id]
- 重啓容器:docker restart [containerid]
- 停止容器:docker stop [容器ID/name]
- 強制停止容器:docker kill 【容器ID/name】
- 刪除已經停止的容器:docker rm
- 一次性刪除多個容器
docker ps -a -q|xargs docker rm
docker rm -f $(docker ps -a -q)
4.3.2 重要命令
-
以守護進程的方式啓動容器:docker run -d centos
注意:使用鏡像centos:latest以後臺模式啓動一個容器
$ docker run -d centos
問題:然後docker ps -a進行查看,會發現容器已經退出?
答案:
很重要的一點:Docker 容器後臺運行,就必須有一個前臺進程。
容器運行的命令如果不是那些一直掛起的命令(比如運行top, tail),就是會自動退出的
這個是Docker的機制問題,比如你的web容器,我們以nginx爲例,正常情況下我們配置啓動服務只需要啓動響應的service即可,例如:service nginx start
但是,這樣做,nginx爲後臺進程模式運行,就導致docker前臺沒有運行的應用,
這樣的容器後臺啓動後,會立即自殺因爲他覺得自己無事可做了
所以:最佳解決方案是,將你要運行的程序以前臺進程的方式運行
-
查看容器日誌: $docker logs -f -t --tail 【num】容器ID
-
-t:加入時間戳
-
-f:跟隨最新的日誌打印
-
--tail:數字,顯示最後多少條‘
-
實例:
-
$docker run -d centos /bin/sh -c "while true; do echo hello zzyy; sleep 2;done"
-
查看容器內的進程 docker top [容器ID]
-
查看容器內部的襲擊: docker inspect 容器ID
-
進入正在運行的容器,並以命令行交互
docker attach [容器ID】
docker exec -t [容器ID] 要做的命令: e.g: docker exec -t 67f1b8e1d497 ls -l /tmp
- 從容器內拷貝文件到主機上: $docker cp 容器ID:【待拷貝文件、文件夾】 【local文件夾】
4.3.3 常用命令
5 Docker 鏡像
5.1 Docker鏡像是什麼?
Docker鏡像是一種輕量級、可執行的獨立軟件包,用來打包軟件運行環境和基於運行環境開發的軟件,它包含運行某個軟件所需的所有內容,包括:代碼、運行時庫、環境變量和配置文件等。
- UnionFS聯合文件系統 --Docker鏡像的底層實現
特性:一次同時加載多個文件系統,但是從外面來看,只能看到一個文件系統,聯合加載會把各層文件系統疊加起來,這樣最終的文件系統包含所有底層的文件和目錄。
- Docker鏡像加載原理:
- 分層的鏡像
以tomcat爲例:一層套一層
- 爲什麼Docker鏡像要採用這種分層結構呢?
- 最大的好處:共享資源
- 比如:有多個鏡像都從相同的base鏡像構建而來,那麼宿主機只需在磁盤上保存一份base鏡像。同時內存中也只需要加載一份base鏡像,就可以爲所有容器服務了。而且鏡像的每一層都可以被共享。
5.2 特點
Docker鏡像都是隻讀的。
當容器啓動時,一個新的可寫層被加載到鏡像的頂部。
這一層通常被稱作“容器層”,“容器層”之下的都叫“鏡像層”
5.3 Docker鏡像的commit操作補充
- $docker commit: 提交容器的副本使之成爲一個新的鏡像
- $docker commit -m = "提交的描述信息" -a=“作者”容器ID 要創建的目標鏡像名:[標籤名]
- Examples:
- Step1:$docker run -it -p 8080:8080 tomcat
- -p: 主機端口:docker容器端口 (兩個端口可以不一樣 -)
- -P:隨機分配端口
- -i:交互
- -t:終端
- Step2:故意刪除tomcat的容器的文檔
docker exec -it 66b71173a36e /bin/bash
ls -l
cd webapps/
rm -rf docs
- Step3:以現在的tomcat容器爲文檔commit一個新的鏡像
docker commit -a="zzyy" -m="tomcat without docs" 66b71173a36e emma/mytomcat:1.2
- Step 4: 與原來的做對比
- 啓動自己的emma/tomcat,他沒有docs
- 啓動原來的tomcat,它有docs
6 Docker容器數據卷 (volume)
先來看看Docker的理念:
- 將運用於運行的環境打包形成容器運行,運行可以伴隨着容器,但是我們對數據的要求希望是持久化的,
- 容器之間希望有可能共享數據
Docker 容器產生的數據,如果不通過docker commit生成新的鏡像,是的數據作爲鏡像的一部分保存下來,那麼當容器刪除後,數據自然就沒有啦
爲了能夠保存數據,我們需要在docker中使用卷。
6.1 數據卷是什麼?
卷:就是目錄或文件,存在於一個或多個容器中。由docker掛載到容器,但不屬於聯合文件系統。因此能夠繞過Union File System提供一些屬於持久化存儲或共享數據的特性。
卷的設計目的:實現數據持久化,完全獨立於容器的生存週期,因此DOcker不會再容器刪除時刪除其掛載的數據卷。
特點:
- 數據卷可在容器之間共享或者重用數據
- 卷中的更改可以直接生效
- 數據卷中的更改不會包含在鏡像的更新中
- 數據卷的生命週期一致持續到沒有容器使用它爲止
6.2 數據卷能幹什麼?
- 容器的持久化
- 容器間繼承+共享數據
6.3 數據卷使用
6.3.1 容器內添加數據卷的方式
方式1:直接命令添加:$docker run -it -v /宿主機絕對路徑目錄:/容器內目錄 鏡像名
-v, --volume list Bind mount a volume
--volume-driver string Optional volume driver for the container
--volumes-from list Mount volumes from the specified container(s)
- 例如
- 1. 創建volume dir in host machine:/Users/Emma/3rd_libs/docker_study/myDataVolume
- 2. 運行並掛載volume:
- docker run -it -v /Users/Emma/3rd_libs/docker_study/myDataVolume:/dataVolumeContainer centos
- 3. 查看是否掛載成功
- 4. 容器和宿主機之間數據共享
- 5. 容器停止退出後,主機修改後數據是否同步 --答案:完全同步
- 6. 命令帶權限:
- 容器內的volume dir只讀,不可寫
- 命令(帶權限): docker run -it -v /宿主機絕對路徑目錄:/容器內目錄:ro鏡像名
方式2:通過DockerFile添加
什麼是Dockerfile?
- JavaEE hello.java ==> hello.class
- Docker images ==> DockerFile
實現步驟:
詳細步驟:
- 之所以用VOLUME指令的原因
- docker build生成鏡像
docker build -f /Users/Emma/3rd_libs/docker_study/test01/DockerFile -t emma/centos .
- 但是主機的volume在哪呢??可以通過docker inspect containerid查看
備註:
6.4 小結
- 數據卷容器是什麼?
- 定義:命名的容器掛載數據卷,其他容器通過掛載這個容器(父容器)實現數據共享,掛在數據卷的容器稱之爲數據卷容器。
- 總體介紹
- 以上一步新建的鏡像emma/centos爲模板並運行容器dc01/dc02/dc03
- 他們已經具有容器卷/dataVolumeContainer1 和/dataVolumeContainer2
- 容器間傳遞共享(--volumes-from)
- Step1: 先啓動一個父容器dc01:
- docker run -it --name dc01 emma/centos
- Step2: dc02和dc03繼承自dc02:
- 格式:--volumes-from
- 命令: dc02和dc03分別在dataVolumeContainer2各自新增內容
-
docker run -it --name dc02 --volumes-from dc01 emma/centos
-
docker run -it --name dc03 --volumes-from dc01 emma/centos
-
- Step3: 分別在3個container的volume中添加文件,發現containers之間可以共享
- 刪除dc01,dc02修改後,dc03可否訪問?? --可以;並不影響volume數據之間的共享
- Step1: 先啓動一個父容器dc01:
- 結論: 容器之間配置信息的傳遞,數據卷的生命週期一直持續到沒有容器使用它爲止!
7 DockerFile解析
回顧上一節創建DockerFile:
-- 1. 手動編寫dockerfile文件,必須符合規範 -- 2. 有這個文件後,直接docker build命令生成自定義經鏡像 -- 3. run |
7.1 什麼是DockerFile?
- DockerFile是用來構建Docker鏡像的構建文件,是由一系列命令和參數構成的腳本
- 構建三步驟:dockerfile-》 docker build --》 docker run
- 文件是什麼樣? --以centos爲例:
其中:scratch就是所有image的祖先
FROM scratch
MAINTAINER https://github.com/CentOS/sig-cloud-instance-images
ADD centos-6-docker.tar.xz /
LABEL org.label-schema.schema-version="1.0" \
org.label-schema.name="CentOS Base Image" \
org.label-schema.vendor="CentOS" \
org.label-schema.license="GPLv2" \
org.label-schema.build-date="20181006"
CMD ["/bin/bash"]
7.2 DockerFile構建過程解析
- Dockerfile內容的基礎知識
- 每條保留至零都必須大寫字母,且後面至少要跟隨一個參數
- 指令按照從上到下順序執行
- #表示註釋
- 每條指令都會創建一個新的鏡像層,並對鏡像進行提交
- Docker執行Dockerfile的大致流程:
- docker從基礎鏡像運行一個容器
- 執行一條指令並對容器作出修改
- 執行類似docker commit的操作提交一個新的鏡像層
- docker再基於剛提交的鏡像運行一個新的容器
- 執行dockerfile中的嚇一跳指令知道所有指令都執行完成
- 小結:
7.3 DockerFile體系結構 (保留字指令)
- FROM - 基礎鏡像,當前的鏡像是基於哪個鏡像的
- MAINTAINER - 鏡像爲活着的姓名和郵箱地址
- RUN - 容器構建時需要運行的命令
- EXPOSE - 當容器對外暴露出的端口
- WORKDIR - 指定在創建容器後,終端默認登錄進來的工作目錄,一個落腳點
- ENV - 用來在構建鏡像過程中設置環境變量
- ADD - 拷貝+解壓。將宿主機目錄下的文件拷貝進鏡像且ADD命令會自動處理URL和解壓tar壓縮包
- COPY - 拷貝。類似ADD,拷貝文件和目錄到鏡像中。將從構建上下文目錄中<源路徑>的文件/目錄複製到新的一層的鏡像內的<目標路徑>位置
- COPY src dest
- COPY ["src","dest"]
- VOLUME - 容器數據卷,用於數據保存和持久化工作
- CMD - 指定一個容器啓動時要運行的命令; DockerFile中可以有多個CMD命令,但只有最後一個生效;CMD會被docker run之後的參數替換
- ENTRYPOINT - 指定一個容器啓動時要運行的命令;ENTRPOINT的目的和CMD一樣,都是在指定容器啓動程序和參數;
- 去CMD的區別:DockerFile中可以有多個CMD,但只有最後一個生效。
- ONBUILD - 當構建一個被繼承的DockerFile時運行命令,父鏡像在被子繼承後父鏡像的onbuild被觸發
7.4 案例
- Base鏡像(scratch): Docker Hub中99%的鏡像都是通過在base鏡像中安裝和配置需要的軟件構建出來的。
- 自定義鏡像MyCentos:
- 初始centos
- 自定義mycentos,使其具備如下:
- 登陸後的默認路徑
- vim編輯器
- 查看網絡配置ifconfig支持
- 初始centos
7.3.1 實現
編寫DockerFile
構建 docker build -f DockerFile路徑 -t 新鏡像名字:Tag .
docker build -f /Users/Emma/3rd_libs/docker_study/test02/DockerFile -t emma/mycentos:1.3 .
利用鏡像run container
docker run -it emma/mycentos:1.3
列出鏡像歷史
CMD/ENTRYPOINT鏡像實例:
- 都是指定一個容器啓動時要運行的命令
- CMD
- DockerFile中可以有多個CMD指令,但是隻有最後一個生效,CMD會被docker run之後的參數替換
- Case -- tomcat講解演示
- docker run -it -p 7777:8080 tomcat
- docker run -it -p 7777:8080 tomcat ls -l
- ENTRYPOINT
- docker run之後的參數會被當做參數傳遞給ENTRYPOINT,之後形成新的命令組合
- Case:
ONBUILD
創建MyTomcat9鏡像
- 要求和步驟
- 執行:
# 運行run:
docker run -d -p 9080:8080 --name myt9
-v /Users/Emma/3rd_libs/docker_study/myDataVolume/tomcat9/test:/usr/local/apache-tomcat-9.0.8/webapps/test #(數據卷)
-v /Users/Emma/3rd_libs/docker_study/myDataVolume/tomcat9/tomcat9logs:/usr/local/apache-tomcat-9.0.8/logs #(數據卷)
--privileged=true #(數據卷寫權限)
Mytomcat9
小結:
8 Docker常用安裝
總體步驟: 搜索鏡像-拉取鏡像-查看鏡像-啓動鏡像-停止容器-移除容器
8.1 安裝Tomcat
8.2 Docker安裝mysql
- Search: docker search mysql
- Pull: docker pull mysql:5.6
- Run mysql
-
啓動交互式運行: docker exec -it 08da34fc52a8 /bin/bash
8.3 Docker安裝Redis
- Pull: docker pull redis:3.2
- Use image:
docker run -p 6379:6379
-v /Users/Emma/3rd_libs/docker_study/myDataVolume/myredis/data:/data
-v /Users/Emma/3rd_libs/docker_study/myDataVolume/myredis/conf/redis.conf:/usr/local/etc/redis/redis.conf
-d redis:3.2 redis-server /usr/local/etc/redis/redis.conf --appendonly yes
9 Docker本地發佈到阿里雲
9.1 本地image發佈到阿里雲流程
9.2 鏡像的生成方法
- DockerFile
- 從容器創建一個新的鏡像: docker commit [OPTIONS] 容器ID [REPOSITORY]:TAG]
- 將本地鏡像push到雲端
- 在阿里雲端創建鏡像倉庫
- 將本地鏡像推送到阿里雲