Docker深刻淺出系列 | Image實戰演練

Docker已經上市不少年,不是什麼新鮮事物了,不少企業或者開發同窗之前也很少很多有所接觸,可是有實操經驗的人很少,本系列教程主要偏重實戰,儘可能講乾貨,會根據本人理解去作闡述,具體官方概念能夠查閱官方教程,由於本系列教程對前一章節有必定依賴,建議先學習前面章節內容。java

本系列教程導航:
Docker深刻淺出系列 | 容器初體驗mysql

課程目標

  • 回顧Container與Image核心知識
  • 瞭解如何製做自定義Image的兩種方式
  • 瞭解Dockerfile的一些經常使用指令
  • 瞭解Image一些經常使用命令
  • 瞭解如何基於現有Image建立新的Image
  • 瞭解如何運行一個Springboot容器

Container與Image核心知識回顧

在上一篇已經提到過,Docker Image是有多層結構,實際上由一層一層的文件系統組成,底層都是共享宿主Linux內核,Image的分層結構是是爲了提升複用性。Image能夠看做是Java的class文件,容器能夠當作是JAVA的對象去理解,下層的每一層鏡像能夠看做是JAVA中的父類,上層鏡像能夠共享底層鏡像的組件,相似JAVA中的繼承規則。
Docker Image 基於 Union file systems作鏡像和容器分層,避免在每次以新容器運行圖像時複製一組完整的文件。將更改分隔爲其自身層中的容器文件系統,容許將同一容器置於從已知內容從新啓動(由於在刪除容器時,更改的圖層將被關閉)。

面向用戶的是Container層,全部用戶新增環境依賴和數據都會保存在容器層,下層Image只可讀、不可修改。linux

Container是一種輕量級的虛擬技術,不須要模擬硬件建立虛擬機啓動內核空間,所以啓動速度很快git

Docker是基於Linux Kernel的Namespace、CGroups、UnionFileSystem等技術封裝成的一種自
定義容器格式,從而提供一套虛擬運行環境。github

  • Namespace:對全局系統資源的一種封裝隔離,使得處於不一樣namespace的進程擁有獨立的全局系統資源,改變一個namespace中的系統資源只會影響當前namespace裏的進程,對其餘namespace中的進程沒有影響,好比pid[進程]、net[網絡]、mnt[掛載點]等
  • CGroups: cgroup和namespace相似,也是將進程進行分組,但它的目的和namespace不同,namespace是爲了隔離進程組之間的資源,而cgroup是爲了對一組進程進行統一的資源監控和限制,好比內存、CPU、進程數等
  • Union file systems:用來作image和container分層

製做Docker Image的兩種方式

  • 經過Dockerfile製做(推薦) - Dockerfile其內部包含了一條條的指令,每一條指令構建一層,所以每一條指令的內容,就是描述該層應當如何構建。
  • 經過Docker commit操做 - 經過docker commit命令反向基於容器副本建立一個新的鏡像文件。可是使用docker commit看不到Image的建立過程,所以對排查問題不友好。

Dockerfile經常使用指令

  • FROM
    指定基礎鏡像,好比FROM centos:6
    FROM centos:6
  • RUN
    在鏡像內部執行一些命令,好比安裝軟件,配置環境等,換行可使用
    groupadd -r mysql && useradd -r -g mysql mysql
  • ENV
    設置變量的值,ENV MYSQL_MAJOR 5.7,能夠經過docker run --e key=value修改,後面能夠直接使
    用${MYSQL_MAJOR}
    ENV MYSQL_MAJOR 5.7
  • LABEL
    設置鏡像標籤
LABEL email="evan08@163.com" 
LABEL name="evan"
  • VOLUME
    定義匿名數據卷。在啓動容器時忘記掛載數據卷,會自動掛載到匿名卷,在啓動容器 docker run 的時候,咱們能夠經過 -v 參數修改掛載點。
    做用:
    • 避免重要的數據,因容器重啓而丟失,這是很是致命的。
    • 避免容器不斷變大。

VOLUME /var/lib/mysqlweb

  • COPY
    將主機的文件複製到鏡像內,若是目錄不存在,會自動建立所須要的目錄,注意只是複製,不會提取和
    解壓
    COPY demo-api.jar /usr/loacl/app/
  • ADD
    將主機的文件複製到鏡像內,和COPY相似,只是ADD會對壓縮文件提取和解壓
    ADD demo-api.jar /usr/loacl/app/
  • WORKDIR
    指定鏡像的工做目錄,以後的命令都是基於此目錄工做,若不存在則建立
WORKDIR /usr/local 
WORKDIR tomcat 
RUN touch test.txt

會在/usr/local/tomcat下建立test.txt文件sql

  • CMD
    容器啓動的時候默認會執行的命令,如有多個CMD命令,則最後一個生效
CMD ["mysqld"] 或CMD mysqld
  • ENTRYPOINT
    和CMD的使用相似,但docker run執行時,會覆蓋CMD的命令,而ENTRYPOINT不會
ENTRYPOINT ["docker-entrypoint.sh"]
ENTRYPOINT ["/bin/bash", "-C","/start.sh"]
  • EXPOSE
    聲明容器運行的服務端口,啓動鏡像時,可使用-p將該端口映射給宿主機
    EXPOSE 3306 3307

更多操做能夠查看菜鳥教程docker


Image實戰篇

經過Dockerfile製做Image

(1)在IDEA建立一個Springboot項目
(2)建立一個Rest Apiapache

@RestController
public class DemoController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello";
    }


}

(3)經過maven命令 mvn clean package打包應用
target目錄會生成了一個demo-api-0.0.1-SNAPSHOT.jar

(4)進入上一章建立的虛擬機Centos7服務器中建立一個目錄demo-dockerfile目錄

  • 使用前一章建立的密碼evan123去登錄Centos7服務器
Connection to 192.168.100.9 closed.
192:centos7 evan$ ssh root@192.168.100.9
root@192.168.100.9's password: 
Last login: Thu Jan 30 03:22:59 2020 from 192.168.100.7
-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory
[root@10 ~]#
  • 建立文件夾
[root@10 /]# mkdir /usr/local/demo-dockerfile

(4)回到宿主機器,上傳demo-api-0.0.1-SNAPSHOT.jar到Centos7服務器demo-dockerfile目錄,我這裏用使用命令行操做,其餘童鞋可使用其餘sfpt工具上傳

192:centos7 evan$ scp Users/evan/development/repository/eshare-docker-in-action/demo-api/target/demo-api-0.0.1-SNAPSHOT.jar  root@192.168.100.9:/usr/local/demo-dockerfile 
root@192.168.100.9's password: 
/etc/profile.d/lang.sh: line 19: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory
Users/evan/development/repository/eshare-docker-in-action/demo-api/target/demo-api-0.0.1-SNAPSHOT.jar: No such file or directory
192:centos7 evan$ scp /Users/evan/development/repository/eshare-docker-in-action/demo-api/target/demo-api-0.0.1-SNAPSHOT.jar  root@192.168.100.9:/usr/local/demo-dockerfile 
root@192.168.100.9's password: 
/etc/profile.d/lang.sh: line 19: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory
demo-api-0.0.1-SNAPSHOT.jar                   100%   18MB 105.8MB/s   00:00    
192:centos7 evan$

(5)回到虛擬機,在剛纔建立的目錄下建立一個Dockerfile文件

192:centos7 evan$ ssh root@192.168.100.9
root@192.168.100.9's password: 
Last login: Thu Jan 30 03:25:43 2020 from 192.168.100.7
-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory
[root@10 ~]# cd /usr/local/demo-dockerfile
[root@10 demo-dockerfile]# mkdir Dockerfile
[root@10 demo-dockerfile]# touch Dockerfile
[root@10 demo-dockerfile]# ls
Dockerfile  demo-api-0.0.1-SNAPSHOT.jar

(6)填入如下內容到Dockerfile

FROM openjdk:8 
MAINTAINER evan 
LABEL name="demo-dockerfile" version="1.0"author="evan" COPY demo-api-0.0.1-SNAPSHOT.jar demo-api-image.jar CMD ["java","-jar","demo-api-image.jar"]

(7)先啓動Docker服務,假如不存在

[root@10 demo-dockerfile]# sudo systemctl start docker

(8)在該目錄下基於Dockerfile構建自定義的鏡像

命令:docker build -t demo-api-image .

運行結果以下:

[root@10 demo-dockerfile]# docker build -t demo-api-image .
Sending build context to Docker daemon  19.32MB
Step 1/5 : FROM openjdk:8
8: Pulling from library/openjdk
146bd6a88618: Already exists 
9935d0c62ace: Already exists 
db0efb86e806: Already exists 
e705a4c4fd31: Already exists 
3d3bf7f7e874: Already exists 
49371c5b9ff6: Already exists 
3f7eaaf7ad75: Already exists 
Digest: sha256:7b7408b997615b4d6aaf6c1f0de8a32182497250288ee0a27b4e98cf14a52fb3
Status: Downloaded newer image for openjdk:8
 ---> 8c6851b1fc09
Step 2/5 : MAINTAINER evan
 ---> Running in 8fb93afccef8
Removing intermediate container 8fb93afccef8
 ---> 1f516267494a
Step 3/5 : LABEL name="demo-dockerfile" version="1.0"author="evan"
 ---> Running in 12cf6c64acf8
Removing intermediate container 12cf6c64acf8
 ---> 5ab38f113669
Step 4/5 : COPY demo-api-0.0.1-SNAPSHOT.jar demo-api-image.jar
 ---> d752dc61c8a9
Step 5/5 : CMD ["java","-jar","demo-api-image.jar"]
 ---> Running in d8bb64f014ee
Removing intermediate container d8bb64f014ee
 ---> cd026463e853
Successfully built cd026463e853
Successfully tagged demo-api-image:latest

(9)基於咱們自定義的image啓動容器,容器命名爲demo-api

docker run -d --name demo-api -p 8999:8080 demo-api-image

(10)查看容器的啓動日誌

[root@10 demo-dockerfile]# docker logs demo-api

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.4.RELEASE)

2020-01-30 04:32:29.537  INFO 1 --- [           main] com.example.demo.api.DemoApiApplication  : Starting DemoApiApplication v0.0.1-SNAPSHOT on 4b90fdd0dd97 with PID 1 (/demo-api-image.jar started by root in /)
2020-01-30 04:32:29.540  INFO 1 --- [           main] com.example.demo.api.DemoApiApplication  : No active profile set, falling back to default profiles: default
2020-01-30 04:32:30.478  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2020-01-30 04:32:30.488  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-01-30 04:32:30.489  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.30]
2020-01-30 04:32:30.540  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2020-01-30 04:32:30.540  INFO 1 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 895 ms
2020-01-30 04:32:30.712  INFO 1 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-01-30 04:32:30.888  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-01-30 04:32:30.890  INFO 1 --- [           main] com.example.demo.api.DemoApiApplication  : Started DemoApiApplication in 1.756 seconds (JVM running for 2.25)

(11)在宿主機器上訪問容器服務,測試Api是否成功部署

[root@10 demo-dockerfile]# curl localhost:8999/hello
Hello

(12)再啓動多一個容器實例測試

[root@10 demo-dockerfile]# docker run -d --name demo-api02 -p 8998:8080 demo-api-image
3029d6b4325a6773ddcacca8d39917b1abfe12d6004cc8a765608f7f2d64edb3
[root@10 demo-dockerfile]# curl localhost:8998/hello
Hello

(12)登錄Docker鏡像倉庫,沒有帳號的童鞋提早到hub.docker.com註冊

[root@10 demo-dockerfile]# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: 10856214
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

(13)推送定製的Docker鏡像到遠程倉庫,鏡像名稱要跟Docker id一致

[root@10 demo-dockerfile]# docker tag demo-api-image 10856214/demo-api-image
[root@10 demo-dockerfile]# docker push 10856214/demo-api-image
The push refers to repository [docker.io/10856214/demo-api-image]
9fb0d7d193ef: Pushed 
a6ded049566a: Mounted from library/openjdk 
e7fe5541de5f: Mounted from library/openjdk 
03ff63c55220: Mounted from library/openjdk 
bee1e39d7c3a: Mounted from library/openjdk 
1f59a4b2e206: Mounted from library/openjdk 
0ca7f54856c0: Mounted from library/openjdk 
ebb9ae013834: Mounted from library/openjdk 
latest: digest: sha256:32afd9d8ca8205d6e667543a66163330c5067c5a37ebd80d53e9563b809e8bb4 size: 2007

(14)查看Image是否已經成功推送到遠程倉庫

(15)從遠程倉庫把Image拉到本地

[root@10 demo-dockerfile]# docker pull 10856214/demo-api-image
Using default tag: latest
latest: Pulling from 10856214/demo-api-image
Digest: sha256:32afd9d8ca8205d6e667543a66163330c5067c5a37ebd80d53e9563b809e8bb4
Status: Image is up to date for 10856214/demo-api-image:latest
docker.io/10856214/demo-api-image:latest

(16)基於遠程10856214/demo-api-image啓動容器

[root@10 demo-dockerfile]# docker run -d --name demo-api03 -p 8997:8080 10856214/demo-api-image
f6907cc3f8b7c21e26111c748de23d923f96f5b2ffef54478ff49d8c03416651
[root@10 demo-dockerfile]# docker ps
CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS              PORTS                    NAMES
f6907cc3f8b7        10856214/demo-api-image   "java -jar demo-api-…"   4 seconds ago       Up 3 seconds        0.0.0.0:8997->8080/tcp   demo-api03
3029d6b4325a        demo-api-image            "java -jar demo-api-…"   About an hour ago   Up About an hour    0.0.0.0:8998->8080/tcp   demo-api02
4b90fdd0dd97        demo-api-image            "java -jar demo-api-…"   About an hour ago   Up About an hour    0.0.0.0:8999->8080/tcp   demo-api
[root@10 demo-dockerfile]#

經過Docker Commit建立Image

(1)查看運行中的容器

[root@10 demo-dockerfile]# docker ps
CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS              PORTS                    NAMES
f6907cc3f8b7        10856214/demo-api-image   "java -jar demo-api-…"   2 hours ago         Up 2 hours          0.0.0.0:8997->8080/tcp   demo-api03
3029d6b4325a        demo-api-image            "java -jar demo-api-…"   3 hours ago         Up 3 hours          0.0.0.0:8998->8080/tcp   demo-api02
4b90fdd0dd97        demo-api-image            "java -jar demo-api-…"   3 hours ago         Up 3 hours          0.0.0.0:8999->8080/tcp   demo-api
[root@10 demo-dockerfile]#

(2)進入咱們在上一節從遠程倉庫拉回來的自定義鏡像內部

[root@10 demo-dockerfile]# docker exec -it demo-api03 bash
root@f6907cc3f8b7:/#

(3)修改容器demo-api03,在容器內部安裝yum工具

  • 嘗試運行yum指令,默認是不帶yum工具,由於容器裏的linux操做系統只保留基本指令
root@f6907cc3f8b7:/# yum
bash: yum: command not found
root@f6907cc3f8b7:/#
  • 查看下容器內部的linux操做系統版本
root@f6907cc3f8b7:/# cat /etc/issue
Debian GNU/Linux 9 \n \l

內置的操做系統用的Debian

  • 使用apt-get更新系統組件
root@f6907cc3f8b7:/# apt-get update
Ign:1 http://deb.debian.org/debian stretch InRelease
Get:2 http://security.debian.org/debian-security stretch/updates InRelease [94.3 kB]
Get:3 http://deb.debian.org/debian stretch-updates InRelease [91.0 kB]
Get:4 http://deb.debian.org/debian stretch Release [118 kB]              
Get:5 http://security.debian.org/debian-security stretch/updates/main amd64 Packages [516 kB]
Get:6 http://deb.debian.org/debian stretch-updates/main amd64 Packages [27.9 kB]
Get:7 http://deb.debian.org/debian stretch Release.gpg [2365 B]               
Get:8 http://deb.debian.org/debian stretch/main amd64 Packages [7086 kB]
Fetched 7936 kB in 1min 18s (101 kB/s)                                         
Reading package lists... Done
  • 安裝容器內置操做系統必要依賴
apt-get install build-essential
  • 下載安裝yum組件
apt-get install yum
  • 測試yum是否安裝成功
root@f6907cc3f8b7:/# yum --help
Usage: yum [options] COMMAND

List of Commands:

check          Check for problems in the rpmdb
check-update   Check for available package updates
clean          Remove cached data
deplist        List a package's dependencies
...

(4)經過以上步驟,咱們已經成功修改了容器,接下來咱們推出容器,基於當前容器版本建立一個新的Image,命名爲demo-api-image-v1

[root@10 demo-dockerfile]# docker commit demo-api03 demo-api-image-v1
sha256:7887668690a3e53c27535669252f67b0391d54443776f1a431f91fe5800958be
[root@10 demo-dockerfile]#

這時候建立出來的Image是默認已經攜帶了yum組件

(5)基於上面更新的新鏡像demo-api-image-v1建立一個容器

[root@10 demo-dockerfile]# docker run -d -it --name demo-api-v1 demo-api-image-v1
6363450e8f7af1f53f935e345d50f7bbfd3ff82bb2409fd5fd75a0f253ed1de8

(6)進入demo-api-v2容器驗證是否已經存在yum組件

[root@10 demo-dockerfile]# docker exec -it demo-api-v1 bash
root@6363450e8f7a:/# yum
You need to give some command
Usage: yum [options] COMMAND

List of Commands:

check          Check for problems in the rpmdb
check-update   Check for available package updates
clean          Remove cached data
deplist        List a package's dependencie
...

附錄

Image經常使用操做

  • 查看本地image列表 docker images docker image ls
  • 獲取遠端鏡像 docker pull
  • 刪除鏡像[注意此鏡像若是正在使用,或者有關聯的鏡像,則須要先處理完] docker image rm imageid docker rmi -f imageid docker rmi -f $(docker image ls)刪除全部鏡像
  • 運行鏡像 docker run image
  • 發佈鏡像 docker push

Container經常使用操做

  • 根據鏡像建立容器 docker run -d --name -p 9090:8080 my-tomcat tomcat
  • 查看運行中的container docker ps
  • 查看全部的container[包含退出的] docker ps -a
  • 刪除container docker rm containerid docker rm -f $(docker ps -a)刪除全部container
  • 進入到一個container中 docker exec -it container bash
  • 根據container生成image docker commit demo-api03 demo-api-image-v1
  • 查看某個container的日誌 docker logs container
  • 查看容器資源使用狀況 docker stats
  • 查看容器詳情信息 docker inspect container
  • 中止/啓動容器 docker stop/start container

項目Demo Github

https://github.com/EvanLeung08/eshare-docker-in-action.git

相關文章
相關標籤/搜索