docker入門篇

  • 2019 年 10 月 5 日
  • 筆記

基礎知識不回顧了,直接上。

docker的安裝與啟動

yum remove docker -y

yum install docker-io -y # 需要先配置好epel源

/etc/init.d/docker start

chkconfig docker on

獲取鏡像

docker pull centos       # 從docker倉庫下載一個鏡像例如:docker pull centos:6.7

docker p_w_picpaths            #列出本地已存在的鏡像

docker p_w_picpaths centos # 查看指定的鏡像

運行

# docker run centos /bin/echo'Hello world'

# docker run -i -t centos:6.7/bin/bash

    -i表示輸入終端保持打開狀態

    -t表示開一個偽終端,並綁定到標準輸入上

    -c限制運行的某個容器的CPU配額【最大默認是1024】

    –cpuset-cpus=  設置可以綁定使用幾個CPU,具體可以看help

    -d 表示後台運行容器,只輸出容器的ID到屏幕

    -P表示–publish-all=false     Publish all exposed ports to random ports

    –hostname=docker1.demo.com 表示修改容器的hsotname

    –name=lnmp1      表示給啟動的容器命名,不用隨機名稱

    –dns=xx.xx.xx.xx 自定義DNS服務器地址【不指定該參數的話,就是要外部主機的/etc/resolv.conf來配置容器】

    –add-host "www.demo.com:192.168.2.2"  在容器的/etc/hosts添加一條指定的DNS解析記錄

    –expose80 –expose 8080       # 暴露端口在外部Expose a port or a range of ports

    –memory1G       限制容器最大使用的內存

    *centos後面如果不指定版本,則默認選擇latest版本

輸入exit或者Ctrl+d退出

# docker run -ti –name test3–hostname=docker1.demo.com –dns=192.168.2.2 –dns=8.8.8.8 lanmp:v1 /bin/bash  # 複雜的寫法

# docker run -d ubuntu:14.04/bin/sh -c "while true; do echo hello world; sleep 1; done" 以後台進程模式運行

# docker logs 後面跟容器的NAMES

當利用 docker run 來創建容器時,Docker 在後台運行的標準操作包括:

檢查本地是否存在指定的鏡像,不存在就從公有倉庫下載

利用鏡像創建並啟動一個容器

分配一個文件系統,並在只讀的鏡像層外面掛載一層可讀寫層

從宿主主機配置的網橋接口中橋接一個虛擬接口到容器中去

從地址池配置一個 ip 地址給容器

執行用戶指定的應用程序

執行完畢後容器被終止

# docker ps 查看在運行中的docker實例進程

# docker logs insane_babbage    查看容器中的標準輸出

# docker stop insane_babbage    停止某個容器

# docker ps可以看到剛才啟動的那個centos容器沒有了

# docker ps -a 可以看到所有的容器(包括已停止的)

# docker start insane_babbage      # 如果加-i參數可以進入交互式的容器

# docker version     查看docker客戶端版本和進程的版本信息

ubuntu容器安裝軟件:

默認安裝好的ubuntu docker是沒有vim和ping這些命令的。

進入容器後,執行

# apt-get update

# apt-get install vim -y

然後vi /etc/apt/sources.list 添加阿里雲的源地址。

# apt-get install inetutils-ping-y

# ping www.qq.com 即可

查看幫助信息

# docker  只輸入docker指令,系統會自動列出全部可用的命令列表

# docker p_w_picpaths –help

創建鏡像方法1:修改鏡像

# docker run -i -t centos:6.7/bin/bash       記下容器的ID,例如:e2d6c890682f

在容器中添加LAMP環境

# yum install httpd mysql mysql-server php php-mysql -y 

# exit 退出容器

# docker commit -m "Add LAMPenv" -a "CentOS_LAMP" e2d6c890682f 6.7lamp   提交更新後的副本

    -m message

    -a author

# docker p_w_picpaths   可以看到已經生成了一個鏡像

# docker run -i -t 6.7lamp/bin/bash      用剛才創建的鏡像啟動容器

另外,可以使用docker commit -m 'my nignx' e2d6c890682fdemo/my_nginx:v1 這種創建帶明顯標誌的鏡像。

啟動的話使用docker run -d -p 88:80 –name "ningx_1" demo/my_nginx:v1 即可。

方法2、dockerfile創建基於centos6.7的nginx的容器

mkdir /opt/docker-file

cd /opt/docker-file

mkdir nginx && cd nginx

vi Dockerfile 內容如下:

# This is My First Dockerfile

# Verson 1.0

# Author: Lee

FROM centos:6.7

MAINTAINER Lee

ADD pcre-8.36.tar.gz/usr/local/src       <— 1、需要事先把這個tar.gz包拷貝到當前目錄下,即和Dockerfile在同一個目錄下

ADD nginx-1.11.5.tar.gz/usr/local/src <—2、如果是個壓縮包,拷到容器後會自動解壓的,無需我們解壓操作

RUN rm -fr /etc/yum.repos.d/*

RUN wget -O/etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo

RUN wget -O/etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo

RUN yum clean all

RUN yum install -y wget gcc gcc-c++ make openssl-devel

RUN useradd -s /sbin/nologin -Mwww

WORKDIR/usr/local/src/nginx-1.11.5

RUN ./configure–prefix=/usr/local/nginx –user=www –group=www –with-http_ssl_module –with-http_stub_status–with-pcre=/usr/local/src/pcre-8.36 && make && make install

RUN echo 'daemon off;' >>/usr/local/nginx/conf/nginx.conf

RUN sed 's@#user  nobody;@user www;@g' nginx.conf

ENV PATH/usr/local/nginx/sbin:$PATH

EXPOSE 80

CMD ["nginx"]

docker build -t dockfile:v2 . 這樣就可以創建鏡像了

啟動剛才創建的nginx docker容器的話,使用docker run -d -p 8888:80 dockfile:v2即可。

參數說明:

指令:

FROM <p_w_picpath>[:tag>]  或者FROM <p_w_picpath>@<digest>   # 必須是第一個非注釋的行,用於指定所用到的基礎鏡像

MAINTAINER <author's detail>

COPY ["<src>", …"<dest>"]       複製本地主機的目錄到容器里的指定目錄

    <src>是要複製的源文件或目錄,支持通配符

    <dest>目標路徑,正在創建的鏡像文件的文件系統路徑(建議使用絕對路徑)

說明:所有新複製生成的目錄文件的UID和GID都是0

例如: COPY /home/template/server.xml/etc/tomcat/server.xml

          COPY *.conf /etc/httpd/conf.d/

注意:src 必須是build上下文的路徑,即不能使用類似../../conf/*.conf,但是還是可以使用絕對路徑例如/home/conf.d/*.conf ;src如果是目錄的話,遞歸複製會自動進行;如果有多個src,包括在src上使用了通配符,此時dest必須是目錄,而且必須得以/結尾。

       dest如果事先不存在,它會被自動創建,包括其父目錄。

ADD 類似COPY指令,額外還支持複製tar格式的文件及URL路徑。【ADD比COPY用得更常見些】

例如:ADD haproxy.cfg /etc/haproxy/haproxy.cfg

     ADDlogstash_*.cnf /etc/logstash/

         ADD http://www.demo.com/download/nginx.conf/etc/nginx/ 【URL格式指定的源文件,下載完成後其目標文件權限為600】

如果src是一個宿主機上的tar文件,則它將被解壓展開成要給目錄(類似tar xf命令,如果通過URL下載的是個tar文件,則不會被自動展開)

ENV    定義環境變量,此些變量可以被當前dockerfile文件中的其它指令所調用,調用格式為$variable_name或${variable_name}

語法:

       ENV<key> <value>  一次定義一個變量

或者 ENV <key>=<value>…  一次可以定義多個變量,如果value中有空白字符,要是進行轉義

如: ENV myName="Tom Lee" myDog='wang cai'

說明:ENV定義的環境變量在鏡像運行的整個過程中一直存在,因此可以使用docker inspect查看,甚至可以用docker run –env=xxx 來修改其值

USER 指定運行容器時,或者運行RUN CMD ENTRYPOINT指令指定的程序時使用的用戶名或者UID

格式: USER <UID>|<Username>

WORKDIR 為後續的RUN、CMD、ENTRYPOINT、COPY、ADD指令配置工作目錄

如:

    WORKDIR/a

    WORKDIRb

    WORKDIRc

    RUNpwd

則最終路徑為 /a/b/c

另外,  WORKDIR還可以調用由ENV定義的環境變量的值,如: WORKDIR $STATEPATH

ENTRYPOINT

VOLUME 在目標鏡像文件中創建一個掛載點,用來掛載主機上的卷或其他容器的卷。一般用來存放數據庫和需要保持的數據等。

    VOLUME<mountpoint>

例如: VOLUME ["/data/mysql","/data/Images"]

注意:如果mountpoint路徑下事先有文件存在,則在掛載完成後,會同時顯示當前的文件和掛載前的文件(AUFS的疊加原理)。

RUN                          

每個RUN都會另起一層,所以建議將多個命令放到一行,減少AUFS的層數。

格式:

RUN <command>    # 會啟動一個shell解釋器

或RUN ["<executeable>","<param1>","<parma2>",…]       # 不會啟動shell解釋器

例如:

       RUNyum install iproute nginx && yum clean all

RUN['/bin/bash','-c','yum','install','httpd']

CMD    設定在docker run時默認執行的命令

格式: CMD <command> 或CMD ["<executeable>","<param1>","<parma2>"]

或CMD["<param1>","<param2>",…]  為ENTRYPOINT指令指定的程序提供默認參數。

如果dockerfile中存在多個CMD指令,則只有最後一個生效。

例如:

       CMD["/usr/sbin/httpd","-c","/etc/httpd/conf/httpd.conf"]

ENTRYPOINT 類似CMD指令,但其不會被docker run的命令行參數指定的指令所覆蓋。且這些命令行參數會被當中參數送給ENTRYPOINT指令指定的程序

如果運行docker run時使用了–entrypoint選項,則此選項的參數可以覆蓋掉dockerfile默認的entrypoint參數。

格式:

       ENTRYPOUNT<command>

       ENTRYPOUNT["executeable","<param1>","<param2>",…] 

例如:

注意:

如果CMD和ENTRYPOINT都存在的話,則CMD的指令會被附加到ENTRYPOINT後,變成ENTRYPOINT的參數。

EXPOSE     用於為容器指定要暴露的端口

格式:EXPOSE<port>[/protocol>][<port>[/<protocol>]]…

如:

       EXPOSE11211/tcp 11211/udp

ONBUILD 配置當所創建的鏡像作為其它新創建鏡像的基礎鏡像時,所執行的操作指令

例如: ONBUILD ADD my.cnf /etc/mysql/my.cnf

注意:ONBUILD不能自我嵌套,且不會觸發。

導出鏡像

# docker save -o/root/centos_lamp_v3.tar centos/lamp:v3

導入鏡像

# docker load–input /root/centos_lamp_v3.tar

或者docker load </root/centos_lamp_v3.tar

# 這將導入鏡像以及其相關的元數據信息(包括標籤等)

移除鏡像

# docker rmicentos/lamp:v3

注意:在刪除鏡像之前要先用dockerrm 刪掉依賴於這個鏡像的所有容器。

想要刪除untagged p_w_picpaths,也就是那些id為<None>的p_w_picpath的話可以用

# docker rmi$(docker p_w_picpaths | grep "^<none>" | awk "{print $2}")

要刪除全部p_w_picpath的話

# docker rmi$(docker p_w_picpaths -q)

刪除已停止的容器

# docker rm -f$(docker ps -a -q)

移除容器

# docker rm5d6da6754d01

停止所有的container,這樣才能夠刪除其中的p_w_picpaths:

# docker stop$(docker ps -a -q)

如果想要刪除所有container的話再加一個指令:

# docker rm$(docker ps -a -q)

從本地文件系統導入一個鏡像

要從本地文件系統導入一個鏡像,可以使用 openvz(容器虛擬化的先鋒技術)的模板來創建: openvz 的

模板下載地址為 templates 。

比如,先下載了一個 ubuntu-14.04 的鏡像,之後使用以下命令導入:

catubuntu-14.04-x86_64-minimal.tar.gz |docker import – ubuntu:14.04

上傳鏡像

docker pushouruser/sinatra

進入容器

在使用 -d 參數時,容器啟動後會進入後台。某些時候需要進入容器進行操作,有很多種方法,包括使用docker attach 命令或 nsenter 工具等

# docker attach 容器NAME

或者docker exec-ti 容器ID /bin/bash

但是使用 attach 命令有時候並不方便。當多個窗口同時 attach 到同一個容器的時候,所有窗口都會同步顯示。當某個窗口因命令阻塞時,其他窗口也無法執行操作了。使用attach進到容器後要退出的話,只能關閉xshell了,使用exit會導致整個容器的退出。

nsenter 這個進入容器的命令也很好用(如果沒有的話需要安裝util-linux-ng)。

方法:

dockerinspect  –format"“.`State`.`Pid`" 容器NAME或者容器ID號      # 結果會輸出一個容器的pid號

nsenter –target 容器的pid號 –mount –uts –ipc –net–pid

上面2條命令可以做成腳本,in.sh 內容如下:

#!/bin/bash

CNAME=$1

CPID=$(dockerinspect  –format"“.`State`.`Pid`" $CNAME)

nsenter–target $CPID –mount –uts –ipc –net –pid

sh in.sh 容器的NAME或者ID號,即可進入容器。

導出容器快照到本地文件

# docker ps -a

# docker export 容器名稱 > ubuntu.tar

導入容器快照為鏡像

# cat ubuntu2.tar |docker import – test/ubuntu:v1

# docker p_w_picpaths

自己基於centos構建nginx容器:

首先啟動一個centos容器,然後在裏面安裝nginx(我這裡是yum安裝的nginx)。

修改nginx的配置文件,加上daemon off; 參數。

然後繼續。下面有2種方法啟動容器時候讓它自動啟動nginx

方法1:

    dockercommit -m 'nginx_v1' eb919426f773 6.7_nginx_v1

    dockerrun -d -p 888:88 –name 'nginx_v1' 6.7_nginx_v1 /usr/sbin/nginx

這樣就可以了。

方法2:

修改容器的/etc/bashrc 加上/usr/sbin/nginx -c/etc/nginx/nginx.conf

    dockerrun -d -p 888:88 –name 'nginx_v1' 6.7_nginx_v1 /bin/bash

docker私有倉庫的搭建

【作為倉庫的虛擬機IP為:192.168.2.11】:

# 必須先啟動docker registry【centos6上是這樣的。在centos7上則變成了一個守護進程,需要用systemctl來啟動】

# docker pullregistry

# docker run -d-p 5000:5000 -v /opt/data/registry:/tmp/registry registry

# docker ps   記下容器NAME為kickass_wright

# 默認情況下,倉庫會被創建在容器的 /tmp/registry 下。可以通過 -v 參數來將鏡像文件存放在本地的指定路徑。

# docker p_w_picpaths   列出當前的鏡像

# docker tag88e44a5cbd17 192.168.2.11:5000/centos/lamp 

格式:dockertag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]

# docker p_w_picpaths

Docker從1.3.X之後,與docker registry交互默認使用的是https,然而此處搭建的私有倉庫只提供http服務,所以當與私有倉庫交互時就會報上面的錯誤。為了解決這個問題需要在啟動docker server時增加啟動參數為默認使用http訪問。

修改docker配置文件將代碼加到/etc/sysconfig/docker的other_args="–insecure-registry192.168.2.11:5000"裏面。

# docker stopkickass_wright       停掉registry容器

#/etc/init.d/docker restart    重啟docker

# docker startkickass_wright      啟動registry容器

# docker push192.168.2.11:5000/centos/lamp       將本地鏡像推送到本機上的私有服務器上

這樣本地鏡像就是上次到私有docker 倉庫了。

我們可以在其他節點測試能否下載這個鏡像。如果沒問題的話,就可以在本機上刪除原有的docker鏡像,如下:

# docker rmi 192.168.2.11:5000/centos/lamp

在Node2節點(192.168.2.12)測試:

# yum installdocker-io -y

修改docker配置文件將代碼加到/etc/sysconfig/docker的other_args="–insecure-registry192.168.2.11:5000"裏面。

#/etc/init.d/docker restart    重啟docker

# docker pull192.168.2.11:5000/centos/lamp          從192.168.2.11的私有倉庫下載鏡像

# docker p_w_picpaths      可以看到已經下載好了相關的鏡像

docker的監控命令:

docker ps [-a]

docker p_w_picpaths

docker stats Container_name # 實時查看某個容器的負載情況

docker top Container_name       # 實時查看某個容器的狀態統計(類似top命令)

 dockerinspect   # 查看容器或鏡像的底層信息

例如:docker inspect -f'“.`Config`.`Hostname`' d413082da04e  類似ansible的 ansible -m setup的輸出格式

此外,還有谷歌提供的CAdvisor web界面的監控工具;Scout工具,Data Dog工具,等。具體可參考: http://dockone.io/article/397

數據卷:

數據卷是一個可供一個或多個容器使用的特殊目錄,它繞過 UFS,可以提供很多有用的特性:

  • 數據卷可以在容器之間共享和重用
  • 對數據卷的修改會立馬生效
  • 對數據卷的更新,不會影響鏡像
  • 卷會一直存在,直到沒有容器使用

*數據卷的使用,類似於 Linux 下對目錄或文件進行 mount

下面創建一個web 容器,並加載一個數據卷到容器的/webapp 目錄:

# docker run -d-P –name web -v /webapp training/webapp python app.py  

# 這樣只寫名容器中的目錄不寫宿主機的目錄的話,實際上是在宿主機的/var/lib/docker/volumes/xxxx/目錄下的。不常用這種寫法。

-v 標記來創建一個數據卷並掛載到容器里。在一次 run 中多次使用可以掛載多個數據卷

*注意:也可以在 Dockerfile 中使用 VOLUME 來添加一個或者多個新的卷到由該鏡像創建的任意容器。

掛載一個主機目錄src/webapp作為容器的數據卷:

# docker run -d-P –name web2 -v /src/webapp:/opt/webapp training/webapp python app.py

# 格式:-v 本地路徑:容器路徑

* 上面的命令加載主機的 /src/webapp 目錄到容器的 /opt/webapp 目錄。這個功能在進行測試的時候十分方便,比如用戶可以放置一些程序到本地目錄中,來查看容器是否正常工作。

* 本地目錄的路徑必須是絕對路徑,如果目錄不存在 Docker 會自動為你創建它。

* 注意:Dockerfile 中不支持這種用法,這是因為 Dockerfile 是為了移植和分享用的。然而,不同操作系統的路徑格式不一樣,所以目前還不能支持。

Docker 掛載數據卷的默認權限是讀寫,用戶也可以通過:ro 指定為只讀。

# sudo docker run-d -P –name web -v /src/webapp:/opt/webapp:ro training/webapppython app.py

-v 標記也可以從主機掛載單個文件到容器中

# docker run –rm-it -v ~/.bash_history:/.bash_history ubuntu /bin/bash   【不同shell版本有所不同】

*注意:如果直接掛載一個文件,很多文件編輯工具,包括 vi 或者 sed –in-place ,可能會造成文件inode 的改變,從 Docker 1.1 .0起,這會導致報錯誤信息。所以最簡單的辦法就直接掛載文件的父目錄。

數據卷容器:

如果你有一些持續更新的數據需要在容器之間共享,最好創建數據卷容器。

數據卷容器,其實就是一個正常的容器,專門用來提供數據卷供其它容器掛載的。

首先,創建一個數據卷容器dbdata,並在其中創建一個數據卷掛載到/dbdata:

# docker run -i-t -v /dbdata –name dbdata ubuntu:12.04/bin/bash

再啟動2個容器測試

# docker run -i-t –volumes-from dbdata –name db1 ubuntu:12.04/bin/bash

# docker run -i-t –volumes-from dbdata –name db2 ubuntu:12.04/bin/bash

# 注意:–volumes-from後面跟的是具備容器卷的那個容器名

此時容器db1和db2都掛載同一個數據卷到相同的/dbdata目錄。三個容器任何一方在該目錄下的寫入,其他容器都可以看到。[即便原來的那個數據卷容器已經停止了]

查看數據卷實際的存放路徑:

docker inspect -f“.`Volumes` 數據卷容器的NAME或ID

map[/dbdata:/var/lib/docker/volumes/7c12ca73fe29f884ea5bee12c54da521c7450705264f76fe8629877302cd48aa/_data]

可以看到這個容器卷是把文件寫入到/var/lib/docker/volumes下面的某個很長的字符串的目錄下的_data/裏面

容器和宿主機間文件拷貝的解決方法:

docker ps 獲取目標容器的ID或者容器的名稱    # 我這裡的是容器ID為52261df2fab6

docker inspect-f'“.`Id`' 容器的ID      # 獲取容器的ID全名稱

得到一串類似52261df2fab612b24b3502c4ad98c22aff70ce9fa641c5c9f735ac2415e92da3

cp /root/test.log/var/lib/docker/devicemapper/mnt/52261d…xxx/rootfs/root/   # 這樣就把宿主機的test.log拷貝到容器的/root/目錄下了。

# 說明:上面的這個方法在CentOS6.7通過yum安裝的docker-io測試通過。我另一台測試機安裝的是docker-engine,則根本沒有/rootfs/這個目錄。

還可以使用多個–volumes-from 參數來從多個容器掛載多個數據卷。

# docker run -i-t -v /dbdata –name dbdata ubuntu:12.04/bin/bash

# docker run -i-t -v /webdata –name webdata ubuntu:12.04/bin/bash

# docker run -i-t –volumes-from dbdata –name db1 –volumes-fromwebdata –name web1 ubuntu:12.04 /bin/bash

此外,也可以從其他已經掛載了數據卷的容器來掛載數據卷。

*注意:

使用 –volumes-from 參數所掛載數據卷的容器自己並不需要保持在運行狀態。

如果刪除了掛載的容器(包括 dbdata、db1 和 db2),數據卷並不會被自動刪除。

如果要刪除一個數據卷,必須在刪除最後一個還掛載着它的容器時使用 "docker rm -v 容器名" 命令來指定同時刪除關聯的容器。這可以讓用戶在容器之間升級和移動數據卷。另外,如果啟動時候加了–rm參數,則容器關閉時自動刪除容器並刪除卷。

利用數據卷容器來備份數據

# docker run -i-t -v /dbdata –name dbdata ubuntu:12.04 /bin/bash

# cp /etc/issue/etc/group /dbdata

另外啟動一個容器,對剛才的容器數據進行備份操作

# docker run –volumes-fromdbdata -v $(pwd):/backup –name bk1 ubuntu:12.04 tar czf/backup/backup.tar.gz /dbdata

# 格式:dockerrun –volumes-from要備份的容器名-v 宿主機目錄:/backup ubuntu:12.04 tar czf /backup/xx.tar.gz 需要備份的容器的卷名稱

*容器啟動後,使用了 tar 命令來將 dbdata 卷備份為容器下的/backup/backup.tar.gz,這個容器執行完就自動退出了(因為沒有-ti 或-d參數),

*同時在宿主機下當前目錄下生成backup.tar.gz壓縮文件(參數-v $(pwd):/backup就是這個作用).

利用數據卷容器來恢複數據

如果要恢複數據到一個容器,首先創建一個帶有數據卷的容器 dbdata2。

# docker run -it-v /dbdata –name dbdata2 ubuntu:12.04 /bin/bash

隨便在/dbdata裏面複製些文件,以便後面恢複數據時用於識別。

然後創建另一個容器,掛載 dbdata2 的容器,並使用tar解壓備份文件到掛載的容器卷中。

#docker run –volumes-from dbdata2 -v $(pwd):/backup ubuntu:12.04 tar xf/backup/backup.tar.gz