我的 docker 探索之路

版權聲明:可以任意轉載,轉載時請標明文章原始出處-ScriptShi

前言

docker處於瞭解並使用的情況,但使用也是在DevOps下使用的,只有一個宏觀的瞭解,因此對docker的各種具體使用也不熟悉,所以決定探索一下,如果內存可以的話,將自己的雲服務器全部docker化。

試驗機介紹

本是在自己的虛擬機裏,但是感覺不是很爽,虛擬機設置個16G內存,8C跑個小docker,對cpu和內存的使用不能真的查看,想在生產環境裏直接看一下效果。

服務器是阿里雲的,今天剛買的一年的學生機,1C 2G 40G-SSD 1M,如下:

安裝的操作系統是centos 7.3

安裝 docker

yum update
curl -fsSL https://get.docker.com/ | sh
service docker start 

設置開機啓動:systemctl enable docker

在阿里雲的“開發者平臺”上進行換源,換成國內鏡像,提高速度(腳本中的xxxxx是個人獨有的,由阿里雲生成的)。

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://xxxxxxxxxxxx.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker 

測試helloworld:docker run hello-world

常見docker命令

列一下docker常用的操作,做個紀念吧。重點會用啓動/停止/刪除、看日誌、進容器裏就可以了。

  • docker ps -a查看所有容器
  • docker exec -it xxxxxx /bin/bash進入容器中並執行一個bash的shell(xxxxx是容器名字或id)
  • docker stop $(docker ps -q)停用全部運行中的容器
  • docker rm $(docker ps -aq)刪除全部容器
  • docker stop $(docker ps -q) & docker rm $(docker ps -aq)一條命令實現停用並刪除容器:
  • docker images | grep -E "(aaa|bbb)" | awk '{print $3}' | uniq | xargs -I {} docker rmi --force {}刪除包含指定名稱的Docker Image(含有aaa或者bbb的映像文件)
  • docker logs -f xxxxxx查看容器的日誌(xxxx:id或name,-f : 查看實時日誌;-tail=10 : 查看最後的10條日誌。)
  • docker runrun的參數有:

     -d, --detach=false         指定容器運行於前臺還是後臺,默認爲false
      -i, --interactive=false   打開STDIN,用於控制檯交互
      -t, --tty=false            分配tty設備,該可以支持終端登錄,默認爲false
      -u, --user=""              指定容器的用戶
      -a, --attach=[]            登錄容器(必須是以docker run -d啓動的容器)
      -w, --workdir=""           指定容器的工作目錄
      -c, --cpu-shares=0        設置容器CPU權重,在CPU共享場景使用
      -e, --env=[]               指定環境變量,容器中可以使用該環境變量
      -m, --memory=""            指定容器的內存上限
      -P, --publish-all=false    指定容器暴露的端口
      -p, --publish=[]           指定容器暴露的端口
      -h, --hostname=""          指定容器的主機名
      -v, --volume=[]            給容器掛載存儲卷,掛載到容器的某個目錄
      --cap-add=[]               添加權限,權限清單詳見:http://linux.die.net/man/7/capabilities
      --cap-drop=[]              刪除權限,權限清單詳見:http://linux.die.net/man/7/capabilities
      --cidfile=""               運行容器後,在指定文件中寫入容器PID值,一種典型的監控系統用法
      --cpuset=""                設置容器可以使用哪些CPU,此參數可以用來容器獨佔CPU
      --device=[]                添加主機設備給容器,相當於設備直通
      --dns=[]                   指定容器的dns服務器
      --dns-search=[]            指定容器的dns搜索域名,寫入到容器的/etc/resolv.conf文件
      --entrypoint=""            覆蓋image的入口點
      --env-file=[]              指定環境變量文件,文件格式爲每行一個環境變量
      --expose=[]                指定容器暴露的端口,即修改鏡像的暴露端口
      --link=[]                  指定容器間的關聯,使用其他容器的IP、env等信息
      --lxc-conf=[]              指定容器的配置文件,只有在指定--exec-driver=lxc時使用
      --name=""                  指定容器名字,後續可以通過名字進行容器管理,links特性需要使用名字
      --net="bridge"             容器網絡設置:
                                    bridge 使用docker daemon指定的網橋
                                    host    //容器使用主機的網絡
                                    container:NAME_or_ID  >//使用其他容器的網路,共享IP和PORT等網絡資源
                                    none 容器使用自己的網絡(類似--net=bridge),但是不進行配置
      --privileged=false         指定容器是否爲特權容器,特權容器擁有所有的capabilities
      --restart="no"             指定容器停止後的重啓策略:
                                    no:容器退出時不重啓
                                    on-failure:容器故障退出(返回值非零)時重啓
                                    always:容器退出時總是重啓
                                    unless-stopped: 除非人工停止,不然自動重啓
      --rm=false                 指定容器停止後自動刪除容器(不支持以docker run -d啓動的容器)
      --sig-proxy=true           設置由代理接受並處理信號,但是SIGCHLDSIGSTOPSIGKILL不能被代理 
  • docker build -t yyyy xxxx構建docker鏡像(yyyy:鏡像的名字,xxxxx:dockerFile的所在目錄)

安裝mysql

安裝最新版的mysql:同時設置容器名字,數據卷分離, 暴露端口,設置密碼,後臺啓動,重啓策略,遠程鏡像名字(不帶版本號默認最新版)

docker run --name mysql -v /data/mysql:/var/lib/mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=你的默認密碼 -d --restart=unless-stopped mysql:5.6.35

常用的幾個就是我安裝mysql時候用到的這些。

進入docker容器內部:docker exec -it mysql bash

進入mysql的shell界面:mysql -uroot -p你的mysql用戶密碼

想起來以前安裝mysql好麻煩呀!docker使我感到開心。

在自己電腦上連接遠程服務器,進行遠程連接測試(首先你需要知道這是不安全的和生產環境絕對不允許的,其次你需要打開防火牆)

如下,測試成功。

SpringBoot 服務的部署

我寫了個只有一個hi的web服務:https://github.com/xjtushilei/jenkins-test.git

並寫了一個簡單的 Dockerfile(下一節簡單講講dockerFile的書寫)

FROM openjdk:8-jdk-alpine
RUN mkdir -p /root/workspace/project
WORKDIR /root/workspace/project
COPY build/libs/*.jar app.jar
#RUN set -ex && ./gradlew build
#RUN cp build/libs/*.jar app.jar

ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/root/workspace/project/app.jar"] 

其實三行就可以搞定,多寫的主要是爲了練習。

我分別嘗試了在docker裏進行構建和在docker外。(具體採取哪種方式要看DevOps了,自己開發的話還是docker外吧,不然每次從maven中央倉庫拉jar包很難受,即便換爲國內的源;如果在docker內構建的話,可以省略外部代碼編譯這一步,直接從代碼到docker鏡像,但是會延長髮布時間)

我們先把代碼拉下來,

yum install git # 新機器,發現沒裝git,尷尬
git clone https://github.com/xjtushilei/jenkins-test.git
cd jenkins-test 

在代碼主目錄下:

  1. 用gradle編譯打包代碼,會生成可運行的jar
  2. 構建 docker鏡像
  3. 運行docker鏡像
yum install java-1.8.0-openjdk  java-1.8.0-openjdk-devel # 新機器,發現沒裝jdk,尷尬
./gradlew  build
docker build -t hi . 

如下所示:構建我自己的docker成功了。

直接非後臺運行:docker run -p 8080:8080 hi就看到了如下熟悉的界面:

遠程測試成功:

到現在爲止,我們也學會了如何發佈自己的docker。我這裏推薦使用阿里雲的容器鏡像服務,特別方便!不用自己拉pull代碼,直接用他們的服務檢測git裏代碼的變化,動態更新鏡像。

Dockerfile 大致流程

  • Dockerfile的第一條指令一般都是FROM,表示從一個基礎鏡像開始構建
  • 執行一條命令對鏡像做出修改
  • 提交更新
  • 基於本次更新,運行新的容器
  • 繼續執行下一條命令

如此反覆執行……

在構建過程中每次生成一層新的鏡像的時候這個鏡像就會被緩存。即使是後面的某個步驟導致構建失敗,再次構建的時候就會從失敗的那層鏡像的前一條指令繼續往下執行。

DockerFile 的書寫

DockerFile分爲四部分組成:基礎鏡像信、維護者信息、鏡像操作指令和容器啓動時執行指令

#第一行必須指令基於的基礎鏡像
From ubutu

#維護者信息
MAINTAINER docker_user  [email protected]

#鏡像的操作指令

RUN apt-get update && apt-get install -y ngnix 
RUN echo "\ndaemon off;">>/etc/ngnix/nignix.conf

#容器啓動時執行指令
CMD /usr/sbin/ngnix 

下面講一下DockerFile常見的指令

FROM

格式爲FROM或FROM:。

第一條指令必須爲FROM指令。並且,如果在同一個Dockerfile中創建多個鏡像時,可以使用多個FROM指令(高版本docker建議搭配as使用)。

MAINTAINER

格式爲MAINTAINER,指定維護者信息。

RUN

格式爲RUN或RUN["executable", "param1", "param2"]

前者將在shell終端中運行命令,即/bin/sh -c;後者則使用exec執行。指定使用其它終端可以通過第二種方式實現,例如RUN ["/bin/bash", "-c", "echo hello"]

每條RUN指令將在當前鏡像基礎上執行指定命令,並提交爲新的鏡像。當命令較長時可以使用\來換行。

CMD

支持三種格式

  • CMD ["executable","param1","param2"]使用exec執行,推薦方式;
  • CMD command param1 param2在/bin/sh中執行,提供給需要交互的應用;
  • CMD ["param1","param2"]提供給ENTRYPOINT的默認參數;

指定啓動容器時執行的命令,每個Dockerfile只能有一條CMD命令。如果指定了多條命令,只有最後一條會被執行。

如果用戶啓動容器時候指定了運行的命令,則會覆蓋掉CMD指定的命令。

EXPOSE

格式爲EXPOSE [...]

告訴Docker服務端容器暴露的端口號,供互聯繫統使用。

這裏僅僅是告訴,如果想給宿主機調用的話,需要run的時候-p 進行端口轉發。

ENV

格式爲ENV。 指定一個環境變量,會被後續RUN指令使用,並在容器運行時保持。

例如

ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH 

ADD

格式爲ADD

該命令將複製指定的到容器中的。 其中可以是Dockerfile所在目錄的一個相對路徑;也可以是一個URL;還可以是一個tar文件(自動解壓爲目錄)。

COPY

格式爲COPY。

複製本地主機的(爲Dockerfile所在目錄的相對路徑)到容器中的。

當使用本地目錄爲源目錄時,推薦使用COPY。這是和ADD的主要區別。

ENTRYPOINT

兩種格式:

  • ENTRYPOINT ["executable", "param1", "param2"]
  • ENTRYPOINT command param1 param2(shell中執行)

配置容器啓動後執行的命令,並且不可被docker run提供的參數覆蓋。

每個Dockerfile中只能有一個ENTRYPOINT,當指定多個時,只有最後一個起效。

VOLUME

格式爲VOLUME ["/data"]

創建一個可以從本地主機或其他容器掛載的掛載點,一般用來存放數據庫和需要保持的數據等。

USER

格式爲USER daemon。

指定運行容器時的用戶名或UID,後續的RUN也會使用指定用戶。

當服務不需要管理員權限時,可以通過該命令指定運行用戶。並且可以在之前創建所需要的用戶,例如:RUN groupadd -r postgres && useradd -r -g postgres postgres。要臨時獲取管理員權限可以使用gosu,而不推薦sudo。

WORKDIR

格式爲WORKDIR /path/to/workdir。

爲後續的RUN、CMD、ENTRYPOINT指令配置工作目錄。

可以使用多個WORKDIR指令,後續命令如果參數是相對路徑,則會基於之前命令指定的路徑。例如

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd 

則最終路徑爲/a/b/c。

docker的其他注意事項

  • 都必須是目錄
  • “必須是容器中的絕對路徑
  • 路徑如果不存在,執行完成之後,docker 會給宿主機創建該目錄;`可以使用相對路徑,但是相對的並不是當前的工作目錄,而是 /var/lib/docker/volumes/`
  • 如果只有一個路徑,比如docker run -it -v,這種情況叫做匿名掛載,表示的是 container 中的位置,宿主機會在`/var/lib/docker/volumes/`下隨機創建一個目錄與 container 中的對應
  • 不管以何種方式 mount,容器銷燬之後,由 -v 在宿主機上創建的目錄不會銷燬

  • <host-path><container-path>都必須是目錄

  • <container-path> 必須是容器中的絕對路徑
  • 路徑如果不存在,執行完成之後,docker 會給宿主機創建該目錄;<host-path>可以使用相對路徑,但是相對的並不是當前的工作目錄,而是/var/lib/docker/volumes/
  • 如果只有一個路徑,比如 docker run -it -v <path> <image>,這種情況叫做匿名掛載,<image>表示的是 container 中的位置,宿主機會在 /var/lib/docker/volumes/下隨機創建一個目錄與 container 中的 <path> 對應
  • 不管以何種方式 mount,容器銷燬之後,由 -v 在宿主機上創建的目錄不會銷燬
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章