Docker学习(三)

可视化

portainer (不常用)

Docker的图形化界面管理工具

1
2
3
4
# 外部8088 内部9000 
# -v 挂载
docker run -d -p 8088:9000\
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

Rancher(CI/CD再用)


镜像是什么

是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件。它包含某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。

如何得到:

  • 远程仓库下载
  • 拷贝
  • 自己制作一个镜像DockerFile

镜像加载原理

UnionFS(联合文件系统)

我们下载的时候看到的一层层就是这个

UnionFS是一种分层、轻量级且高性能的文件系统,它支持文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下.

特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

docker的镜像实际上由一层一层的文件系统组成,这种层级文件系统就是UnionFS

bootfs(boot file system),在Docker镜像的最底层是bootfs,这一层与典型的Linux、Unix系统是一样的,它主要包含bootloader和kernel,bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载掉bootfs

rootfs(root file system),在bootfs之上,包含的是Linux系统中的/dev /proc /bin /etc 等标准目录和文件,rootfs就是各种不同的操作系统发行版,如ubantu,centos

对于一个精简的OS,rootfs可以很小,只包含最基本的命令,因为底层直接用host的kernel。

分层理解

分层的镜像

下载的日志输出,可以看到是一层一层的在下载

为什么采用这种分层结构 ?

最大的好处就是资源共享,比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。

查看镜像分层方式可以通过docker image inspect命令

特点

Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部。

这一层就是通常说的容器层,容器之下的都叫镜像层。

如何commit镜像

1
2
3
docker commit 提交容器成为一个新的副本
# 和git类似
docker commit -m="提交的描述信息" -a="作者" 容器id 容器镜像名:[TAG]

容器数据卷

数据?如果数据都在容器中,那么容器删除,数据就会丢失!需求:数据可以持久

容器之间可以有一个数据共享的技术,docker容器中产生的数据,同步到本地

目录挂载,将容器内的目录挂载到linux上。

总结一句话,容器的持久化和同步操作,容器间也是可以数据共享的。

使用

方式1:直接使用命令挂载 -v

1
2
3
4
-v 主机目录:容器内目录
-p 主机端口:容器内端口

docker run -it -v /home/ceshi:/home centos /bin/bash

是双向的同步,哪怕容器已经停止。

好处:以后修改只需在本地修改即可。

安装mysql

思考:mysql的数据持久化问题

1
2
3
4
5
6
7
(base) root@linux:/home/cpss# docker pull mysql:5.7

# 运行,需要数据挂载
# 安装启动mysql时,需要配置密码的!
# -d 后台运行
(base) root@linux:/home/cpss# docker run -d -p 3310:3306 -v /data2/mysql/conf:/etc/mysql/conf.d -v /data2/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root --name mysql01 mysql:5.7
72180bd20207e871aebdc0a06fddfe10e30d39561620c78558328b9ac0a30b9c

具名和匿名挂载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 匿名挂载
-v 容器内路径
docker run -d -P --name nginx01 -v /etc/nginx nginx

# 查看所有的volume情况,匿名卷挂载
(base) root@linux:/data2/mysql# docker volume ls
# 这种就是匿名挂载,在-v只写了容器内的路径,没有写容器外的路径!

# 具名挂载
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
(base) root@linux:/data2/mysql# docker volume ls
DRIVER VOLUME NAME
local juming-nginx

# 通过-v 卷名:容器内路径
# 查看一下这个卷

所有的docker容器内的卷,没有指定目录的情况下都是在 /var/lib/docker/volumes/xxxxx/_data

通过具名挂载可以方便的找到一个卷,大多数情况在使用的是具名挂载。

1
2
3
4
# 如何确定是具名挂载还是匿名挂载, 还是指定路径挂载
-v 容器内路径 # 匿名挂载
-v 卷名:容器内路径 # 具名挂载
-v /宿主机路径:容器内路径 # 指定路径挂载

扩展

1
2
3
4
5
6
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx

# 通过 -v 容器内路径:ro rw改变读写权限
# 容器对我们挂载出来的内容就有限定了
# ro readonly 只要看到ro就说明这个路径只能通过宿主机来操作,容器内部是无法操作的。

方式二、dockerfile 创建镜像时就挂载出来

Dockerfile 就是用来构建docker镜像的构建文件

通过脚本可以生成镜像,镜像是一层一层的,脚本一个个的命令,每个命令都是一层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
(base) root@linux:/data2/docker-volume# pwd
/data2/docker-volume
(base) root@linux:/data2/docker-volume# vim dockerfile1
(base) root@linux:/data2/docker-volume# cat dockerfile1
FROM centos

VOLUME ["volume01","volume02"]

CMD echo "---end---"

CMD /bin/bash
(base) root@linux:/data2/docker-volume# docker build -f dockerfile1 -t zuo/centos:1.0 .
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos
---> 300e315adb2f
Step 2/4 : VOLUME ["volume01","volume02"]
---> Running in 26da05b75834
Removing intermediate container 26da05b75834
---> 5ae4812f35a4
Step 3/4 : CMD echo "---end---"
---> Running in 29c52fec2f47
Removing intermediate container 29c52fec2f47
---> cb1793533f3d
Step 4/4 : CMD /bin/bash
---> Running in c4bc1543fe44
Removing intermediate container c4bc1543fe44
---> c635584bb2a8
Successfully built c635584bb2a8
Successfully tagged zuo/centos:1.0


(base) root@linux:/data2/docker-volume# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
zuo/centos 1.0 c635584bb2a8 59 seconds ago 209MB



# 创建dockerfile文件,名字可以随机
# 文件中的内容 指令(大写) 参数
FROM centos
每个命令就是镜像的一层

这个卷是匿名挂载,一定有外部的目录

数据卷容器

两个mysql同步数据 —volumes-from

1
2
3
4
# 启动3个容器,通过我们刚才自己的写镜像启动
(base) root@linux:/data2/docker-volume# docker run -it --name docker01 zuo/centos:1.0

(base) root@linux:/data2/docker-volume# docker run -it --name docker02 --volumes-from docker01 zuo/centos:1.0

容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器为止

一旦持久化到了本地,本地的数据是不会删除的。

DockerFile

dockerfile 是用来构建docker镜像的文件,命令参数脚本

构建步骤:

  • 编写一个dockerfile文件
  • docker build构建成为一个镜像
  • docker run 运行镜像
  • docker push 发布镜像(docker hub,阿里云镜像仓库)

构建过程

基础知识

  • 每个保留关键字指令都是大写字母
  • 执行从上到下顺序执行
  • 每个指令都会创建提交一个新的镜像层

dockerfile是面向开发的,我们以后要发布项目做镜像,要写。

指令

1
2
3
4
5
6
7
8
9
10
11
12
FROM          # 基础镜像,一切从这里开始构建
MAINTAINER # 镜像是谁写的,姓名+邮箱
RUN # 镜像构建时要运行的命令
ADD # 步骤,添加内容
WORKERDIR # 镜像的工作目录
VOLUME # 挂载的目录
EXPOSE # 暴露端口
CMD # 指定容器启动时需要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT # 指定容器启动时需要运行的命令,可以追加命令
ONBUILD # 当构建一个被继承 Dockerfile
COPY # 类似ADD 将文件拷贝到镜像中
ENV # 构建的时候设置环境变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
FROM ubuntu:18.04  # 指定基础镜像 如果为scratch代表从下一行开始是镜像的第一层
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html # RUN指令用来执行命令,每一行代表新建docker的一个layer
#能在一个layer内执行的指令就通过&& 进行联接,并可应用shell中的换行符\
#在dockerfile每层都要检查,下载,展开的多余文件,以及缓存等能删除的尽量都去掉

COPY #COPY 指令将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置。
COPY package.json /usr/src/app/ # 将当前上下文路径的json文件复制到image的指定路径下

AND #丰富了COPY的功能,但是会降低构件image速度,如果不需要自动解压缩,则不推荐使用该指令

CMD # ????????? 还没理解

ENTRYPOINT # 当存在 ENTRYPOINT 后,CMD 的内容将会作为参数传给ENTRYPOINT,从而达到了我们预期的效果。

ENV #用来设置环境变量 ENV <key> <value> 或 ENV <key1>=<value1> <key2>=<value2>...
ENV VERSION=1.0 DEBUG=on \
NAME="Happy ONE"

ENV LD_LIBRARY_PATH=\
$LD_LIBRARY_PATH:\
$NAME/alpha

ARG # ARG <参数名>[=<默认值>] Dockerfile 中的 ARG 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 docker build 中用 --build-arg <参数名>=<值> 来覆盖

ARG DOCKER_USERNAME=library # 注意:在FROM之前定义的ARG参数,会消失,在FROM后需要重新定义
# ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的。

VOLUME # 用于指定image启动时挂载到容器中的默认卷,而不是写入容器存储层
VOLUME /data # VOLUME ["<路径1>", "<路径2>"...] 或 VOLUME <路径>
在image启动时可替换
docker run -d -v mydata:/data xxxx #其中的 -v mydata:/data 就是挂载宿主机的卷到容器内

EXPOSE # EXPOSE <端口1> [<端口2>...] EXPOSE 指令是声明容器运行时提供服务的端口,这只是一个声明,在容器运行时并不会因为这个声明应用就会开启这个端口的服务
# 在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口

WORKDIR # WORKDIR <工作目录路径> 使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。

USER # USER <用户名>[:<用户组>] 指定当前用户
HEALTHCHECK
ONBUILD
LEBEL
SHELL #SHELL 指令可以指定 RUN ENTRYPOINT CMD 指令的 shell,Linux 中默认为 ["/bin/sh", "-c"]
Dockerfile 多阶段构建

创建一个字节的centos

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1 编写dockerfile文件
FROM centos
MAINTAINER zuo<com>

ENV MYPATH /usr/local
WORKERDIR $MYPATH

RUN yum -y install vim # 你想让他干啥

EXPOSE 80

CMD echo $MYPATH
CMD echo "----end----"
CMD /bin/bash

# 2通过这个文件构建镜像
docker build -f mydockerfile-centos -t mycentos:0.1 .

# 3测试运行
docker run -it mycentos

查看docker镜像构建历史

CMD 和 ENTRYPOINT 的区别

ENTRYPOINT 是可以追加命令的

做一个tomcat镜像

  • 准备镜像文件,tomcat压缩包,jdk的压缩包
  • 编写dockerfile文件,官方命名 Dockerfile,build会自动寻找这个文件,就不需要-f 指定了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
FROM centos
MAINTAINER zuo<com>

COPY readme.txt /usr/local/readme.txt
ADD jdk-8ull-linux-x64.tar.gz /usr/local/ # 会自动解压
ADD apache-tomcat-9.0.22.tar.gz /usr/local/

RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH

ENV JAVA_HOME /user/local/jdk1.8.0_11
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CLASSPATH_HOME /usr/local/apache-tomcat-9.0.22
ENV CLASSPATH_BASH /usr/local/apache-tomcat-9.0.22
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080

CMD /usr/local/apache-tomcat-9.0.22/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.22/bin/logs

构建镜像

1
2
3
docker build -t diytomcat .

docker run -d -p 9090:8080 --name zuotomcat -v /home/zuo/build/tomcat/test:/usr/local/apache-tomcat-9.0.22/webapps/test -v /home/zuo/build/tomcat/tomcatlogs/:/usr/local/apache-tomcat-9.0.22/logs diytomcat

发布自己的镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
(base) root@linux:/home/cpss# docker login --help

Usage: docker login [OPTIONS] [SERVER]

Log in to a Docker registry.
If no server is specified, the default is defined by the daemon.

Options:
-p, --password string Password
--password-stdin Take the password from stdin
-u, --username string Username


(base) root@linux:/home/cpss# docker login -u zzuuoo666
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


docker push zzuuoo666/diytomcat:1.0 # 就可以了 不加信息可能会被拒绝
# 如果镜像上传过被拒绝,可以添加一个tag
docker tag ID zzuuoo666/tomcat:1.0
docker push zzuuoo666/tomcat:1.0

小结