- Docker 基礎概念

Docker託管到GitHub上:https://github.com/docker/docker-ce

>> Docker 安裝

1、Linux-Ubuntu 安裝 Docker / Windows 安裝 Docker

2、Docker啓動服務:systemctl start docker
若出錯,刪除/etc/docker/daemon.json:rm -f daemon.json

3、配置Docker加速鏡像拉取;

4、安裝Compose;


>> Docker 概念

~ 什麼是容器技術

容器技術:是一種依託於Linux內核的虛擬化的技術;是操作系統級別的虛擬化;

容器是直接運行在操作系統內核之上的用戶空間,所以容器虛擬化也稱爲“操作系統級虛擬化”,容器技術可以讓多個獨立的用戶空間運行在同一臺宿主機上;但是容器只能運行與宿主機相同或相似的操作系統,例如:Ubuntu服務器中只能運行RedHat Enterprise Linux,不能運行Windows;

Linux的內核特性:控件組(control group)、命名空間技術(namespace),使得容器與宿主機之間的隔離更加徹底,容器有獨立的網絡和存儲棧,有自己的資源管理能力,這使得同一臺宿主機上可以共存多個容器;

~ 什麼是Docker

Docker就是裝應用(網站、程序、系統)的一種容器;它可以將應用的代碼打包,然後在服務器之間輕鬆的遷移;

  • 可以理解爲:輕量級的虛擬機,把應用程序放在獨立環境中運行;
  • 優點:快速的持續集成,服務的彈性伸縮,部署簡單;節省機器資源;跨平臺;
  • Docker設計的目的:是加強開發人員寫代碼的開發環境與應用程序部署的生產環境的一致性;

~ Docker容器化技術與虛擬機技術的區別

在這裏插入圖片描述
傳統裝軟件:在硬件上安裝操作系統,然後再操作系統上直接安裝軟件;
在這裏插入圖片描述
現在服務器server上不裝操作系統,而是安裝Hypervisor,然後將Hypervisor進行互連,這就表示這個互連的Hypervisor能使用下面所有的服務器資源(CPU、內存等);

互連的Hypervisor是一個虛擬化操作系統;

在虛擬化操作系統之上再安裝操作系統,然後再操作系統上安裝軟件;這樣就能使用這個整體的虛擬化操作系統來調度所有硬件的資源,分配給上面的各個虛擬操作系統;

在這裏插入圖片描述
在自己的電腦上安裝虛擬機就是:硬件上安裝宿主機(就是自己的操作系統),宿主機之上安裝虛擬化技術(VMware),再在VMware上安裝虛擬機(客戶機Ubuntu),然後再安裝軟件;

使用Docker與VM的區別:
安裝系統時,虛擬機必須要完整的虛擬出一塊硬件資源(CPU、內存),佔用的是底層服務器的資源,這部分資源是不能被共享的,然後再在硬件之上完整的創建一個操作系統;
而Docker直接使用宿主機的內核與資源,使用Docker創建的操作系統之間共享宿主機的內核與資源;

Eg:宿主機內存16G
使用VMware創建一個Ubuntu,分配2G內存,和一個CentOS,分配2G內存,那麼宿主機只剩下12G內存可分配;
在Ubuntu上若需要使用3G的空間,就會出現內存溢出;
在CentOS上使用了1G的空間,那麼就會有1G的空間浪費掉,其他的操作系統不能使用;

使用Docker不用給它分配任何資源,因爲Docker使用的資源直接從宿主機獲取;若在Docker上安裝app1需要使用4G內存時,直接從宿主機拿來用就可以了;

DOcker可以有效利用宿主機的全部資源,虛擬機只能利用分配給它的部分資源;

Docker 優勢:

  • 更高效的利用系統資源;
  • 更快速的啓動時間;
  • 一致的運行環境;
  • 持續交付和部署;
  • 更輕鬆的遷移;
  • 更輕鬆的維護和擴展;

~ Docker容器的技術組件

  • 原生的Linux容器格式libcontainer (Docker容器的默認格式),或流行的容器品臺lxc;
  • Linux內核的命名空間,用於隔離文件系統、進程、網絡:
    • 文件系統隔離:每個容器都有自己的root文件系統;
    • 進程隔離:每個容器都運行在自己的進程環境中;
    • 網絡隔離:容器間的虛擬網絡接口和IP地址都是分開的;
    • 資源隔離和分組:使用cgroup將CPU和內存之類的資源獨立分配給每個Docker容器;
  • 寫時複製:文件系統都是通過寫時複製創建的,這就意味着文件系統是分層的、快速的、而且佔用的磁盤空間更小;
  • 日誌:容器產生的STDOUT、STDERR、STDIN這些IO流都會被收集並記入日誌,用來進行日誌分析和故障排除;
  • 交互式shell:用戶可以創建一個爲tty終端,將其連接到STDIN,爲容器提供一個交互式shell;

~ Docker思想

(1)集裝箱思想:任何東西都可以裝進集裝箱,並且各種貨物都被集裝箱標準化了,集裝箱與集裝箱之間互不影響;
Docker使用集裝箱的思想 將程序和依賴一起打包,程序放到哪裏都不會缺東西,不用每次都配置環境;

(2)標準化思想

  • 運輸方式標準化:將程序部署到倉庫,其他電腦使用時直接從倉庫拉取;(使用簡單的命令即可完成操作)
  • 存儲方式標準化:從存儲倉庫拉取程序時,不需要關心程序存在電腦中的什麼位置,要運行、停止程序只需要執行簡單的命令即可;
  • API接口標準化:使用docker提供的命令執行所有的應用;(eg:啓動Tomcat服務器和啓動其他服務器的命令不一樣,但是使用docker 就可以使用統一的命令完成)

(3)隔離的思想:docker比虛擬機輕量,可以快速的創建、銷燬;各個程序之間互不干擾;

  • 1、不同的應用程序可能會有不同的應用環境,比如Java開發的軟件和Python開發的網站依賴的軟件就不一樣,若把它們依賴的軟件都安裝在一個服務器上可能會發生衝突,比如訪問端口衝突;這時候就要隔離開發的兩個網站;可以在服務器上創建不同的虛擬機,在不同的虛擬機上放置不同的應用,但是虛擬機的開銷比較高;docker可以實現虛擬機隔離應用的環境的功能,並且開銷比虛擬機小;

  • 2、若開發軟件的時候用的是Ubuntu,但是運維管理的都是centos,運維在把你的軟件從開發環境轉移到生產環境的時候就會遇到一些Ubuntu轉centos的問題,比如:有個特殊版本的數據庫,只有Ubuntu支持,centos不支持,在轉移的過程當中運維就得想辦法解決這樣的問題。這時候要是有docker你就可以把開發環境直接封裝轉移給運維,運維直接部署你給他的docker就可以了,而且部署速度快

  • 3、在服務器負載方面,如果你單獨開一個虛擬機,那麼虛擬機會佔用空閒內存的,docker部署的話,這些內存就會利用起來;

~ Docker能做什麼

Docker的應用場景:

  • 加速本地開發和構建流程,使其更加高效、更加輕量化;開發可以構建、運行、分享Docker容器,容器可以在開發環境中構建,然後提交到測試環境、生產環境;
  • 能夠讓獨立的服務或應用程序在不同的環境中,得到相同的運行結果;
  • 可以用來創建隔離的環境來進行測試;

~ Docker解決什麼問題

一個Javaweb程序的執行需要依賴:最底層的操作系統、系統上的JDK、Tomcat、代碼、配置文件;

  • 操作系統變了,可能導致程序無法運行,比如程序調用了某些系統命令,換了一個操作系統,就調用失敗;
  • JDK版本改變,導致程序無法運行,比如class文件使用JDK1.7編譯,電腦上安裝的是JDK1.6,就會發生class版本識別不了;
  • Tomcat:舊版本的配置在新版本中不支持;
  • 代碼引用了電腦D盤某一個文件,換了一個電腦就找不到文件路徑;
  • 配置文件少了,或者配置是和系統相關的,換了個系統就會出錯;

Docker將操作系統、JDK、Tomcat、代碼、配置文件,都裝在集裝箱裏,打包部署到服務器上,在本機上怎麼運行,在服務器上就怎麼運行;

1、Docker解決了運行環境不一致帶來的問題;
2、服務器上同時運行多個程序,一個程序掛了,可能導致其他程序無法正常運行,docker的隔離性解決了這一個問題;
把程序都放在docker裏面運行,docker會在啓動時給每一個程序限定最大使用的CPU內存硬盤,某一個程序發生死循環,掛的只有它自己,其他程序不受影響;


>> Docker 體系結構、核心技術:鏡像/倉庫/容器

在這裏插入圖片描述

~ Docker 架構模式

Docker 使用客戶端-服務器 (C/S) 架構模式,通過在客戶端(一個命令行工具)使用遠程API(一整套RESTFul API)向服務器(Daemon)發出請求來管理和創建Docker容器,Daemon將完成所有工作並返回結果給客戶端;

可以在同一臺宿主機上運行守護進程和客戶端,也可以從本地的Docker客戶端 連接到 運行在另一臺宿主機上的遠程Docker守護進程;

docker build:構建鏡像,然後上傳到Docker倉庫上,使用鏡像的時候再由目的地從倉庫上拉取鏡像;

docker pull:客戶端發送docker pull命令到docker daemon(守護進程),告訴daemon要拉取某個鏡像,docker daemon現在本機查找鏡像是否存在,若存在,並且是所需要的版本,就不會做任何操作,否則就會到docker的倉庫裏面查找所需要的鏡像名字,找到了就會從docker倉庫拉取到本地;

docker run:將命令從本機發送到本機的docker daemon,docker daemon檢查鏡像是否在本機已經存在,若不存在,就相當於執行了一個docker pull的操作從倉庫拉取到本機,然後把鏡像通過一定的方式運行起來,變成docker的容器;

Docker運行一個程序的過程就是:去倉庫 把鏡像 拉取到本地,然後用命令將鏡像運行起來,變成容器;
Docker 容器通過 Docker 鏡像來創建,鏡像與容器的關係類似於面向對象中類與對象的關係;

~ Docker 倉庫

docker鏡像中心:https://hub.docker.com/explore/
網易蜂巢鏡像中心:https://c.163yun.com/hub#/m/home/

  • 鏡像保存在倉庫中,而倉庫存在於Registry中,默認的Registry是由Docker公司運營的公共的Registry服務,即Docker hub

  • 每個鏡像倉庫都可以存放多個鏡像,可以使用docker pull命令來拉取某鏡像倉庫中的所有內容(以標籤名tag來區分的所有鏡像);使用docker images來列出本地的所有鏡像;

  • 可以在創建容器的時候,通過在倉庫名後面加上一個冒號和標籤名來指定該倉庫中的某一鏡像:
    docker run -t -i --name containerName ubuntu:12.04 /bin/bash
    構建容器時最好指定倉庫的標籤,以便可以準確的指定容器的來源;不同標籤創建出的容器會有所不同;

  • Docker Hub中有兩種類型的倉庫:

    • 用戶倉庫user repository:由Docker社區中的用戶創建提供的,這些鏡像沒有經過Docker公司的確認和驗證,so使用有風險;
      用戶倉庫命名:用戶名/倉庫名;
    • 頂層倉庫top-level repository:由Docker內部人員來管理;由Docker公司和由選定的能提供優質的基礎鏡像的廠商管理(eg:Fedora鏡像)
      頂層倉庫命名:只有倉庫名;

~ Docker 鏡像與容器 image/container

  • 鏡像本質上就是一系列文件;可以包括應用程序的文件,也可包括運行環境的文件;

  • 容器本質上就是一個進程,類似虛擬機,具有隔離性;
    可以想象成一個虛擬機,每個虛擬機都有自己的文件系統;可以把下圖整個部分看成是一個容器的文件系統,也就相當於一個虛擬機裏面的所有文件系統,容器與虛擬機的區別是,容器裏面的文件系統是分層的,並且除了第一層是可讀可寫的,下面各層都是隻讀的;
    一個程序運行時需要寫一些日誌、文件,或者對系統的某些文件進行修改,所以容器在第一層創建了一個可讀可寫的文件系統;如果程序運行時要寫一個鏡像中的一個文件,需要將鏡像文件拷到容器的最上層,然後再進行修改;修改之後,當應用讀一個文件的時候,會從頂層開始查找,沒找到纔會找下一層;
    由於第一層的容器可以修改,而下層的鏡像不可以修改,所以一個鏡像可以生成多個容器獨立運行,互不干擾影響;

  • 鏡像是Docker生命週期中的構建或打包階段,容器是啓動或執行階段;

  • 本地鏡像都保存在Docker宿主機的/var/lib/docker目錄下,每個鏡像都保存在Docker所採用的存儲驅動目錄下面,如aufs/devicemapper
    所有容器都保存在/var/lib/docker/containers目錄下;

  • Linux存儲技術:聯合文件系統UnionFS,是一種分層的文件系統,可以將不同的目錄掛到同一個虛擬文件系統下;
    聯合文件系統可以在同一個文件夾下看到其他兩個文件夾裏面的內容,通過這種方式,聯合文件系統就可以實現文件系統的分層;Docker鏡像就是利用這種分層的概念來實現的鏡像的存儲;
    聯合加載指的是一次同時加載多個文件系統,但是在外面看起來只能看到一個文件系統;聯合加載會將各層文件系統疊加到一起,這樣最終的文件系統會包含所有底層的文件和目錄;

  • 容器的文件系統:
    這裏寫圖片描述

  • Docker鏡像是由文件系統疊加而成的;

    • 最低層是一個操作系統的引導:引導文件系統bootfs,用戶幾乎不會和bootfs有什麼交互,當一個容器啓動後,它將會被移到內存中,而bootfs則會被卸載;
    • 第二層是一個具體的操作系統:root文件系統rootfs,位於bootfs之上;rootfs可以是一種或多種操作系統(Debian、Ubuntu);rootfs永遠是隻讀狀態;
    • 第三層是一些相關的軟件的鏡像:Tomcat、JDK;
    • 第四層存放應用代碼;
  • 底下四層是鏡像層都是隻讀的,只有最上面容器層是可讀可寫的;

  • 每一層都加載完成之後,這些文件都會被看做是同一個目錄;相當於只有一個文件系統;

  • Docker將這些底層文件系統稱爲**鏡像;(指的是單個文件系統,不是經過聯合加載技術形成的一整個文件系統,即位於bootfs之上的各個rootfs) 最底部的鏡像稱爲基礎鏡像**(base image),它是所有上面其他鏡像的父鏡像

  • 當從一個鏡像啓動一個容器時,Docker會構建出一個鏡像棧,並且在該鏡像棧的最頂層加載一個讀寫文件系統(讀寫層),這個讀寫層再加上其下面的鏡像層,以及一些基礎配置數據,就構成了一個容器在Docker中運行的程序就是在這個讀寫層中執行的

  • 當Docker第一次啓動一個容器時,初始的讀寫層是空的,當文件系統發生變化時,這些變化都會應用到這一層上;Eg:若要修改一個文件,這個文件首先會從讀寫層下面的只讀層複製到該讀寫層,該文件的只讀版本依然存在,但是已經被讀寫層中的該文件副本所隱藏,這種機制稱爲 “寫時複製(copy on write)”

  • 容器都是可以修改的,都有自己的狀態,並且是可以啓動和停止的;容器的這種特點,加上鏡像分層框架,使得我們可以快速構建鏡像並運行包含我們自己的應用程序和服務的容器;

  • 鏡像可以有相同的鏡像ID,但是標籤名不同;

  • Docker在文件系統內創建鏡像,使用這個鏡像開啓一個容器,該容器擁有自己的網絡IP地址、以及一個用來和宿主機進行通信的橋接網絡接口

~ Docker 虛懸鏡像

使用docker images命令查看鏡像時會看到有些鏡像鏡像名和標籤都是<none>,這些鏡像就是虛懸鏡像;

這個鏡像原本是有鏡像名和標籤的,原來爲 mongo:3.2,隨着官方鏡像維護,發佈了新版本後,重新 docker pull mongo:3.2 時,mongo:3.2 這個鏡像名被轉移到了新下載的鏡像身上,而舊的鏡像上的這個名稱則被取消,從而成爲了 。除了 docker pull 可能導致這種情況,docker build 也同樣可以導致這種現象。由於新舊鏡像同名,舊鏡像名稱被取消,從而出現倉庫名、標籤均爲 的鏡像。這類無標籤鏡像也被稱爲 虛懸鏡像(dangling image) ;

可以用下面的命令專門顯示這類鏡像:$ docker image ls -f dangling=true
刪除虛懸鏡像:$ docker image prune


>> Docker守護進程 (引擎)

安裝完Docker之後,需要確認守護進程是否運行;Docker以root權限運行它的守護進程,來處理普通用戶無法完成的操作(如掛載文件系統);docker程序是Docker守護進程的客戶端,同樣也需要以root身份運行;

Docker安裝完成後默認會立即啓動守護進程,守護進程監聽/var/run/docker.sock這個套接字文件,來獲取來自客戶端的Docker請求;若系統中存在名爲docker的用戶組,Docker就會將該套接字的所有者設置爲該用戶組,這樣docker用戶組的所有用戶都可以直接運行Docker,而不需要再使用sudo命令了;

單個用戶需要使用sudo命令,用戶組用的不需要使用sudo命令,這方便了docker用戶組對Docker的使用,但是存在安全隱患:docker用戶組對Docker具有與root用戶相同的權限;所以用戶組中應該只添加確實需要使用Docker的用戶和程序;

~ 配置Docker守護進程

  • 運行Docker守護進程時,可以使用-H標誌指定不同的網絡接口端口配置,例如:
    sudo /usr/bin/docker -d -H tcp://0.0.0.0:2375,將Docker守護進程綁定到宿主機上的所有網絡接口;Docker不會自動檢測到網絡的變化,我們需要通過-H選項來指定服務器的地址:例如,把守護進程的端口改成4200,那麼運行客戶端時就必須指定docker -H :4200;若不想每次運行客戶端時都加上-H標誌,可以設置環境變量DOCKER_HOSTexport DOCKER_HOST=“tcp://0.0.0.0:2375”

  • 也可以通過-H標誌指定一個Unix套接字路徑sudo /usr/bin/docker -d -H unix://home/docker/docker.sock

  • 也可以同時綁定多個地址sudo /usr/bin/docker -d -H tcp://0.0.0.0:2375 -H unix://home/docker/docker.sock

  • 也可以通過在命令前指定DEBUG=1參數來輸出更詳細的信息;在使用Upstart的Ubuntu系統下,Docker守護進程生成的日誌輸出都保存在/var/log/upstart/docker.log文件中:DEBUG=1 /usr/bin/docker -d

  • 要想這些改動永久生效,需要編輯Docker啓動配置文件:/etc/default/docker文件,此文件用來設置Docker啓動時運行的各種選項;修改Docker守護進程啓動時的啓動選項:DOCKER_OPTS變量

~ 檢查守護進程是否正在運行

在Ubuntu中,若Docker是通過軟件包安裝的話,可以運行Upstart的status命令來檢查Docker守護進程是否正在運行:sudo status docker;也可以使用sudo start/restart/stop docker來啓動/重啓/停止Docker守護進程;

但是使用這些命令會報錯:status: Unable to connect to Upstart: Failed to connect to socket /com/ubuntu/upstart: Connection refused

是因爲:The error message means your Ubuntu is not using Upstart.
From Ubuntu 15.04, systemd is now the default init process instead of Upstart, and as a result some commands have changed.
With systemd, you can instead check the status of, for example, docker with the command:sudo service docker start/stop/restart/status


>> 鏡像構建上下文

執行docker build -t imageName .命令最後面有個.,表示當前目錄,是在指定構建鏡像上下文路徑;

  • Docker build的工作原理
    Docker 在運行時分爲 Docker 引擎(服務端守護進程)和客戶端工具;Docker 的引擎提供了一組 REST API,而如 docker 命令這樣的客戶端工具,則是通過這組 API 與 Docker 引擎交互,從而完成各種功能;因此,雖然表面上我們好像是在本機執行各種 docker 功能,但實際上,一切都是使用的遠程調用形式在服務端(Docker 引擎)完成;也因爲這種 C/S 設計,讓我們操作遠程服務器的 Docker 引擎變得輕而易舉;

在這裏插入圖片描述
在執行docker命令的時候,其實是在請求docker的服務端,docker服務端會將請求的處理結果返回給客戶端;

在這裏插入圖片描述

當我們進行鏡像構建的時候,並非所有指令都會通過RUN指令完成,經常會將一些本地文件複製進鏡像,比如COPYADD指令等;而docker build命令在構建鏡像時,並非在本地進行構建操作,而是將構建的命令發送給服務端,由服務端接收指令完成鏡像的構建操作;

構建的時候,用戶會通過.指定構建鏡像的上下文,docker build命令得知這個路徑後,會將該路徑下的所有內容打包,然後將壓縮包同build指令一起發送給服務端,服務端收到構建的build指令和上下文壓縮包後,會解壓縮,從而獲得構建鏡像所需要的一切文件,然後根據指令,結合解壓縮的文件,完成鏡像的構建工作;

Dockerfile中的COPY ./package.json /app/指令,並不是要複製docker build命令所在的目錄下的package.json文件,也不是複製DOckerfile所在目錄下的package.json文件,它不復制在複製宿主機下的任何文件,而是複製上下文目錄下的package.json文件;

這個上下文目錄指的是複製隨build指令一起上傳到服務端的壓縮文件解壓後的文件目錄;

COPY 這類指令中的源文件的路徑都是相對路徑,相對於構建上下文的路徑;

COPY ../package.json /app/中,..指的是服務端存放解壓縮文件的上級目錄,是服務端的目錄,有什麼誰也不知道;

>> Docker網絡三種模式

Linux利用namespace(命名空間)進行資源的隔離,Eg:PIDnamespace隔離進程,network namespace隔離網絡;每個network namespace都提供一個獨立的網絡環境(網卡、路由等);

  • docker容器默認情況下會分配一個獨立的network namespace,也就是網絡類型中的bridge(橋接)模式;

  • 若啓動容器時指定Host模式,那麼容器將不會獲得一個獨立的network namespace,而是和主機共同使用一個,這個時候容器將不會再虛擬出自己的網卡,配置自己的IP等,而是會使用宿主機上的端口,也就是說在docker上使用網絡 和在主機上使用網絡是一樣的;

  • 還有一種網絡類型:None,沒有網絡;這種情況docker將不會跟外界的任何東西進行通訊;

使用bridge模式時涉及到一個問題:它使用的網絡有獨立的namespace,那麼就需要一種技術:端口映射,使容器上的端口可以在主機上訪問到;

docker可以指定把容器內的某一個端口,和容器主機上的某一個端口之間做一個映射,當訪問主機上的這個端口的時候,就是訪問容器裏面的那個端口;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章