by Devin Yang

建立於: 6年前 ( 更新: 6年前 )

Docker的功能很類似VM(虛擬機器),但是Docker不是VM。
這是Docker與Linux核心的關係。
Docker與Linux的關係,中文圖片。
 
Docker的工作流程(Build、Ship & Run)
1. Build an image: 使用一個叫Dockerfile的純文字檔,來指定我們想要東西綁進image內,諸如: 基本的OS、函式庫及應用程式等,建好的image是一個唯讀的樣板,我們可變更container,並透過commit container來產生一個新的image。
2. Ship the image: 經由Dockerh Hub或你私人的倉庫(private repository),你可以非常輕易的使用docker發佈這個應用程式或開發環境,
基本上這裡已經有大量的官方(official)預建好的image了,隨時可拿來用。
3. Run a container: 要能夠跑container在一台主機上,我們需安裝Docker,
可把他部署成微服務(不同的container跑不同的服務),
我的D-Laravel Project一個Laravel平台的開發環境,就是使用微服務架構。

在下圖中,使用Dockerfiler建立image,通常抓現成的官方image,
用docker run可自動抓下來image並產生container,
我們可以把更多的東西放入container內,
再commit這個container成為一個新的image,再更新push到DockerHub上,
提供給別人使用。

上方投影片的出處

Docker Engine使用了Linux Kernel(核心)的新功能  Namespaces Control groups
用來隔離出工作空間,我們稱為容器(Container),所以不需要像VM安裝一整個作業系統。

Control groups 這裡簡稱 Cgroups Cgroups 允許您在系統運行的用戶定義的任務組(執行序)中,
分配資源(例如CPU時間,系統記憶體、網路頻寬或這些資源的組合),
Namespaces :  用來隔離和虛擬化一系列執行序( processes )。

Create a Container

docker run 指令建容器
當我們安裝好Docker後,我們可以執行如下指令(例如Ubuntu的Linux環境下,需sudo)
sudo docker run alpine echo Hello World
上方使用alpine linux建立的Docker image,只有5mb大小。
如果我們未安裝這個image會自動安裝,如果有裝了,Docker就會直接執行,建立這個容器。
在上方的例子中並未指定tag,就會使用最新版本(latest)。
如果我們要指定版本,可補上:3.5,例如alpine:3.5。

如果不想每次都打sudo,可以執行如下指令,把你的使用者,加入docker群組。
sudo usermod -aG docker ${USER}
例如,我在AWS EC2的主機,預設的使用者是ubuntu,那麼<user>就改成ubuntu,執行完後,
登出再登入bash測試,就會發現,不需要打sudo囉。
docker run hello-world
上方測試,使用hello-word的image來顯示資料。

下方實際執行不需sudo了,在下方的圖片中同時也發現到了,我們電腦不存在hello-world這個image時,
Docker會自動幫我們下載。

Docker Client and Daemon.

1. Client/Server的架構。
2. Client取得使用者的輸入,並且送給Daemon.
3. Daemon進行builds,run及distributes containers.
4. Client及Daemon可以執行在相同的主機或不同的主機上。
5. Client有命令列Client及GUI(Kitematic)兩種。

下方指令,用來查看Client及Server的版本:
docker version

Docker Containers and Images.

Images  
-是一個唯讀的樣版,用於建立Containers。  
-是由你自己建立或是其他的Docker用戶建立。  
-儲存在Dockerhub或是你自己本地端的local Registry.  
Containers
-隔離的運用程式平台
-Container就是你所有應程式執行及安裝的地方
-Container基於一個或多個映像檔(Images)

Registry and Repository

以Docker Hub為例,Reigistry內有很多Repo,在Repo內會有很多的images.
Registry與Repository中文圖片
可以把Dockerhb想像成是Docker的App Store.

Docker的效益

Sepration of concerns.
- 開發者可以專心的在於他們的Apps上(Developers focus on building their apps)。
- 系統工程師專注於部屬 (System admins focus on deployment)。

Fast development cycle
- 如果需要可以輕易的開啟新的container,跑更多的應用程式在主機上。

如何查看host裝了那些images

可以使用 docker images 查看已安裝的images。 不指定tag時,會預設使用latest版。

建立並執行Container(creating a container)

例如:
docker run ubuntu:14.04 echo "Hello World"


Container with Terminal
-使用-i及-t旗標
-i 代表告訴docker去連接到container的STDIN.
-t 旗標,會取得一個pseudo-terminal.

Container內的程序(process)停了,就會同時停止container.
例如:  進入bash之後離開.
docker run -it centos

所以下方的指令如下:
docker run centos echo "TEST"
這個process執行完後,container就停了。
你輸入docker ps,並不會看到上方的echo "TEST"這個contaienr的process.


Container ID

用下方指令可以看執行中的containers及container id
docker ps

列出所有的containers,如果用
docker ps -a

可以看到之前所有建立的並且停止的container.

Running in Detached Mode

用-d進入detached mode
docker run -d centos ping 127.0.0.1 -c 1000
我們可以打
docker ps
查看,這個container的狀態會是執行中。


執行 docker logs <short id> 可以看到結果,如果加上-f,就相當於tail -f指令。
docker logs c0299f4dc228 -f

docker run -d -P nginx 可以進行port mapping
再用 docker ps 查看
docker ps的畫面

上方可以看到,建立了本地主機(host)的32856。

Commit container

先用 docker ps -a 查出所有的containers
docker ps -a
例如,上圖中我有兩個container
再用docker commit指令,建立新的image,如下指令
docker commit c0299f4dc228 my_new_image

記得嗎?image是唯讀的,container才能被寫資料,在進行 Debug 及測試時很有用,
透過commit想保留最新的狀態到image中,這樣下次run這個image時,
產生出來的container就會是我們最後commit的狀態了。

我們可以用 docker images 查看是否有這個my_new_image。

一般而言,我們應該要用Dockerfile來管理我們image的變更

用Dockerfile建images

可以git clone這個repo下來測試.
https://github.com/DevinY/fpm
進入clone下來的fpm工作目錄後,
cd 7.1/apache (進入7.1/apache資料夾)
這個資料夾內,會有一個Dockerfile.
我們就可以用下方指令來build自己的image了。下方的指令中,最後有一個(點).代表查看目前目錄下的Dockerfile,用他來建image。
docker build -t testimage:1.0 .

如何用Dockerfile重build image實際操作,可以參考下方影片連結:
如何重build新的php-fpm image給D-Laravel使用。

執行已停止的container

我們可以用docker start來執行停止中的container,
首先如下方指令,列出所有的container:

1. docker ps -a
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS                      PORTS               NAMES
 8d2f21c4b5fc        alpine              "echo Hello World"   7 minutes ago       Exited (0) 2 minutes ago                       nervous_mestorf

2. 我們可以透過CONTAINER ID或是Name,來重新執行一次echo Hello World,加上-a是因為,
要把container內的標準輸出轉發出來,這樣才能顯示出Hello World在畫面上.
docker start -a 8d2f21c4b5fc
Hello World

(題外話: 如果使用docker-compose時,docker-compose up -d時會建立執行container,docker-compose down時,會移除container)

Docker rm移除Container
docker rm 指令來移除container.
我們可以指定Container id或名稱來刪除container.
1. docker ps -a (列出所有的container)
2. docker rm <container name 或id>
Container必需要在停址的狀態才有辨法刪除,STATUS還是Up我是無法移除的。

如何取得Terminal access.

指令如下:
docker exec -i -t [container ID] /bin/bash
例如,我要進入D-Laravel的web container,那麼可以用如下指令(Container ID或name都OK)
docker exec -ti dlaravel_web_1 bash
這裡 dlaravel_web_1 是Container的名稱
 

登入docker

如果有註冊了dockerhub的帳號,就可以用
docker login

把自己的image push到dockerhub上,我們需先在dockhub上註冊帳號。
docker push deviny/centos:6.6
The push refers to a repository [docker.io/deviny/centos]
網路
本機host會開8080在左邊,而nginx是 container 使用port 80,
下方指令的意思代表了,我們開瀏覽器 localhost:8080 就能開啟nginx的網頁服務了。
docker run -d -p 8080:80 nginx

Mount a Volume

-當執行或建立一個container時卷宗被掛載(Volumes are mounted when creating or executing a container.
-可以被映射到主機資料夾(Can be mapped to a host directory)
-卷宗的路徑必需是絕對路徑(Volume paths specified must be absolute)

執行一個新的container並且掛載資料/myvolume到container的檔案系統內(我們要掛載的資料夾是主機上的絕對路徑)
docker run -d -P -v /myvolume nginx

執行一個新的container並且map(映射)/data/src資料夾,由主機(host)到container內的/test/src資料夾。
docker run -i -t -v /data/src:/test/src nginx

Creating a Link

(官方已列為不建議使用了,未來將被移除)
Warning: The  --link  flag is a deprecated legacy feature of Docker. It may eventually be removed. 

Docker container networking

User-defined Network,Docker官方文件參考

Docker預設會連到default bridge,container之間可用IP互通。 
如果您要讓彼些容器名稱(container name)可以被解析成IP,
我們需使用user-defined networks (使用者定義的網路)

User-defined networks 練習:
讓Container在同一個網路下可以ping到彼此的Container Name
一、建立一個user-defined網路(這裡我取名叫 dodoro_net )
docker network create --driver bridge dodoro_net

#列出網路指令
docker network ls

二、讓兩個Container在同一個 user-defined 的網路( dodoro_net )中,就可以用container name(容器名稱)ping到彼此
1. 建立第一個資料庫的container,並使用--network,設定網路為 dodoro_net
docker run --network=dodoro_net --name db -e MYSQL_ROOT_PASSWORD=secret -d mysql:5.7.17

2. 建立第二個PHP-Apache的contaner,也使用相同的 dodoro_net網路
docker run --network=dodoro_net -d --name website php:7.1.6-apache

3. 進入website container,ping mysql的container name,在step 1,我把資料庫的container命名為db.
docker exec -ti website bash

4.在Website的container內。
ping db
 


上方的筆記中有提到,用 docker rm [container id或name] ,可以用來移除停止的 contaiener
那麼要移除 image 怎麼做呢?
可以用 rmi   (就想成 Remove Image 就對囉,要先把停止的相關container移除後,才能移除image哦)
docker rmi [Image ID]  

關念再確立

希望您能確實了解,這些指令的用途:
docker run      (建立並執行container)
docker start    (啟動一個或多個停止的containers)
docker exec    (在啟動中的container內,執行一個命令)

HELP

如何取得指令的幫助? 例如我們想了解docker start的用法,可以執行如下指令:
docker help start
 

Tags: docker

Devin Yang

文章內容無法一一說明,如果您有什麼不了解處,歡迎提問哦:)

No Comment

Post your comment

需要登入才可留言!

類似的文章


docker

用樹莓派安裝Docker及docker-compose

本文簡單介紹我們如何在Raspberry Pi上安裝docker及docker-compose。

php,docker,dlaravel

我建立的phpenv容器環境簡單介紹

沒時間拍介紹影片,我就來隨便抓些畫面介紹我使用的容器環境deviny/phpenv。https://github.com/DevinY/phpenvphpenv算是我之前D-Laravel開源專案的進化版本,概念上延用了很多Dlaravel的操作方式。容器的更新上偏向使用者自行控制去Build自己的image,所以我不太會去更動版號了,其實D-Laravel的php版號,好像我也很久沒動啦:p&nbsp;

dlaravel,docker

D-Laravel學習三階段

閒聊D-Laravel的使用的三階段,為何使用D-Laravel。 因為D-Laravel使用的設定檔都相當的簡單,極適何Docker的初學者學習, 並且就自不懂Docker運用的使用者,也可以借住./console及./create兩個指令建立專案。