一、docker简介
1.1 为什么会有docker的出现?
以前啊,开发工程师,项目开发完了之后,在本地运行没有问题,打包成war包,交给运维,运维要在linux上部署,部署需要安装个个软件,比如你项目中用到了mq,redis,es等等,结果运维运行出问题了,但是你本地运行没问题,两个人就吵起来了。其实是环境不一样,可能软件版本也不一样。
还有以前搞集群,运维每台服务器都要装相同的软件,server01,server02,server03,这里有三台服务器,运维每台服务器都要装相同的软件,redis,es,mq等等
docker怎么来解决这些问题呢?
第一个问题解决:开发工程师把本地运行的,一些环境配置,一些软件redis,es,mq 什么版本的,装到一个箱子里面,然后给运维,运维直接用开发工程师给的这些环境在服务器上部署。这样就避免了版本环境不一致的问题。
第二个问题解决:运维工程师把这些redis,mq,es软件做成一个镜像,然后在其他服务器上面直接安装就好了,不要每个软件在每个服务器都安装一边。
1.2 docker 三要素
Person
- 镜像 – 就是模板。一个镜像可以创建多个容器。相当于java里面的类(Class Person)。
- 容器 – 是镜像创建的运行实例。相当于java里面类创建的实例(new Person)。
- 仓库 – 集中存放镜像文件的场所。
二、docker-HelloWord镜像
2.1 在虚拟机上 centos 7 安装docker
省略。。。(自己在网上搜教程,一大把。官网也有。)
2.2 阿里云加速器
配置一下,然后让它生效。
2.3 hello-word
查看docker版本
# docker version
启动docker
# systemctl start docker
运行第一个hello-world
# docker run hello-world
run 干了什么?
三、docker命令
3.1 帮助命令
查看docker版本信息
# docker version
查看docker个人信息
# docker info
查看docker帮助命令
# docker -help
3.2 镜像命令
查看docker本地所有镜像
# docker images
repository:表示镜像的仓库源
tag:镜像的标签
image ID:镜像ID
created: 镜像创建时间
size:镜像大小
同一个仓库源可以有多个TAG,代表这个仓库源的不同版本,我们使用REPOSITORY:TAG 来定义不同的镜像。
如果你不指定版本,默认使用 latest ,例如你使用centos ,docker默认使用 centos:latest
参数说明:
-a:列出本地所有镜像(含中间镜像层)
-q:只显示镜像ID
–digests:显示镜像的摘要信息
–no-trunc:显示完成的镜像信息
注意:镜像是分层的,就好比maven里面的依赖关系一样。你下载一个jar,他可能依赖其它jar包
去dockerHub上搜索镜像
# docker search XXX镜像的名字
参数说明:
-s:列出收藏数不小于指定值的镜像
–no-trunc:显示完成的镜像描述
–automated:只列出 “自动化构建” 类型的镜像
下载镜像(默认[: latest])
# docker pull XXX镜像名
# docker pull XXX镜像名 [: tag]
docker镜像删除命令
# docker rmi XXX镜像名/ID
删除单个镜像
# docker rmi -f 镜像名/ID
删除多个镜像
# docker rmi -f 镜像名1 镜像名2 ...
删除所有镜像
# docker rmi -f $(docker images -qa)
注:-f 强制删除的意思
3.3 容器命令
新建并启动容器
# docker run [options] image [command][arg...]
options 说明(常用):
–name 容器新名字:为容器指定一个名称;
-d:后台运行容器,并返回容器ID,也是启动守护式容器;
-i:以交互模式运行容器,通常与 -t 使用;
-t:为容器分配一个伪输出终端,通常与 -i 使用;
-P:随机端口映射;
-p:指定端口映射,有一下四种模式
ip:hostPort:containerPort
ip::containerPort
hostPort:containerPort
containerPort
列出当前所有正在运行的容器
# docker ps [options]
options 说明(常用):
-a:列出当前所有正在运行的容器+历史上运行过的
-l:显示最近创建的容器
-n:显示最近n个创建的容器
-q:只显示容器编号
–no-trunc:不截断输出
退出容器
1.容器停止并退出
# exit
2.容器不停止退出
# ctrl+p+q
启动容器
# docker start 容器名/ID
重启容器
# docker restart 容器名/ID
停止容器
# docker stop 容器名/ID
强制关闭容器
# docker kill 容器名/ID
删除容器
# docker rm 容器ID
强制删除容器
# docker rm -f 容器ID
删除多个容器
# docker rm -f $(docker ps -aq)
# docker ps -aq | xargs docker rm
四、docker命令(重要)
启动守护式容器
# docker run -d 容器名
查看容器日志
# docker logs -f -t --tail 容器ID
-t:加入时间戳
-f:跟随最新的日志打印
–tail:数字显示最后多少条
查看容器内运行的进程
# docker top 容器ID
查看容器内部的细节
# docker inspect 容器ID
操作容器,但不进入
# docker exec -it 容器ID bashShell
重新进入(一般和ctrl+p+q 配合使用)
# docker attach 容器ID
从容器内拷贝文件到主机上
# docker cp 容器ID:容器内路径 目标主机路径
五、docker镜像原理
5.1 Union文件系统(UnionFS)
Union文件系统是一种分层,轻量级并且高性能的文件系统,它支持对系统文件的修改作为一次提交来一层层的叠加.
Union文件系统是docker镜像的基础
5.2 docker镜像加载原理
docker镜像的最底层是bootfs.
5.3 为什么docker镜像要采用这种分层结构呢?
其实最主要的就是 资源共享 这个思维,你下载一个tomcat镜像其实里面包含了centos\jdk等等其他的,如果你在下载其他资源这时候就不要再下载已经存在的镜像了.
这里不作详细说明,感兴趣的同学可以去查阅资料.
六、docker镜像commit
docker commit 提交容器副本使之成为新的镜像
dcoker commit -m="提交描述信息" -a="作者名" 容器ID 新创建镜像名:[版本号]
写个案例:
现在我这边有一个tomcat镜像,我现在启动这个tomcat镜像,正常访问.
查看这个tomcat的文档信息,也没有问题.
下面我来把这个tomcat文档删了
我们再看一下页面
ok,这时候文档已经访问不了了.下面我们就把这个容器打包成一个镜像.
下面我们把所有容器都停了吧,再来启动我们刚刚自己生成的nodocumenttomcat,为了和之前的做出区别换个端口吧,8089
打开页面看效果,按理说文档应该是没有的,我们看是不是
ok,案例写完了.
七、docker容器数据卷
容器数据卷是用来做数据持久化的!
7.1 容器内添加数据卷
docker run -it -v /宿主机路径:/容器内路径 镜像名/ID
我们来试一下这个命令
这个是容器的centos
这个是主机centos
看一下容器信息
我们在宿主机新建一个test文件,写了一段话,看看容器里面会不会有这个文件?
容器里面是有的哦,说明这两个文件是同步的
这个是容器对主机只读权限.
docker run -it -v /宿主机路径:/容器内路径:ro 镜像名/ID
之前是这样
现在是这样子的
在容器里创建文件的时候提示read-only
7.1 用DockerFile添加数据卷
7.1.1 什么叫DockerFile?
由一系列用于根据基础镜像构建新的镜像文件的专用指令序列组成;
先看一下DockerFile文件结构:
FROM: FROM是Dockerfile里的第一条指令(必须是),后面跟有效的镜像名(如果该镜像你的本地仓库没有则会从远程仓库Pull取)。然后后面的其它指令FROM的镜像中执行。
MAINTAINER: 用于提供信息的指令,用于让作者提供本人的信息;不限制其出现的位置,但建议紧跟在FROM之后;
RUN: 运行命令,命令较长使可以使用\来换行。推荐使用上面数组的格式
CMD: CMD指定容器启动是执行的命令,每个Dockerfile只能有一条CMD命令,如果指定了多条,只有最后一条会被执行。如果你在启动容器的时候也指定的命令,那么会覆盖Dockerfile构建的镜像里面的CMD命令。
ENTRYPOINT: 和CMD类似都是配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。
USER: 指定运行容器时的用户名和UID,后续的RUN指令也会使用这里指定的用户。
EXPOSE: 设置Docker容器内部暴露的端口号,如果需要外部访问,还需要启动容器时增加-p或者-P参数进行分配。
ENV: 设置环境变量,可以在RUN之前使用,然后RUN命令时调用,容器启动时这些环境变量都会被指定
ADD: 将指定的<src>复制到容器文件系统中的<dest> 所有拷贝到container中的文件和文件夹权限为0755,uid和gid为0
VOLUME: 如果mountpoint路径下事先有文件存在,docker run命令会在卷挂载完成后将此前的文件复制到新挂载的卷中;
WORKDIR: 切换目录,为后续的RUN、CMD、ENTRYPOINT 指令配置工作目录。
ONBUILD : ONBUILD不能自我嵌套,且不会触发FROM和MAINTAINER指令;
ARG: ARG指定了一个变量在docker build的时候使用,可以使用--build-arg <varname>=<value>来指定参数的值,不过如果构建的时候不指定就会报错。
COPY: 用于从docker主机复制文件至正在创建的映像文件中;
其实就是相当于一个.class文件.
看一下tomcat的DockerFile,你会发现它是依赖于jdk的.
我们先写一个DockerFile,后面会再跟大家讲一下这些参数.
首先我们在根目录下创建一个mydocker文件夹
再创建一个Dockerfile文件
开始编写我们的文件,保存退出
使用命令,根据DockerFile文件生成镜像
docker build -f /mydocker/Dockerfile -t jikang0821/centos .
-f : 指明DockerFile文件位置
. : 当前路径
运行这个命令
我们来运行这个镜像,箭头指向的是我们添加的数据卷
它真的和我们用 docker run -it -v /宿主机路径:/容器内路径 镜像名/ID
效果一样吗?
那么对应的主机文件生成在哪了呢?这里交给大家一个命令快速查看容器卷和主机对应的位置
# docker inspect -f "{{.Mounts}}" 容器ID
有了吧?ok,大功告成.
八、数据卷容器
第七章我们说了容器数据卷,那么什么是数据卷容器呢?
数据卷容器:命名的容器挂载数据卷,其他容器通过挂载这个(父容器)实现数据共享,挂载数据卷的容器,称之为数据卷容器.
--volumes-from
类似于java中的继承,我们之前不是通过DockerFile文件构建了一个镜像,然后又用这个镜像启动了一个容器,如果我们再用这个镜像启动另一个容器并且这个容器要--volumes-from
(继承)上一个容器,这就是容器之间的数据共享,挂载数据卷的容器就是数据卷容器.
给大家写个案列,看一下吧.
这是我们上面用dockerFile文件build的镜像,然后生成的容器4814609ae6bb,能理解吧?
下面我们再用这个jikang0821/centos镜像生成另一个容器,并且要继承上一个容器4814609ae6bb
docker run -it --volumes-from 4814609ae6bb jikang0821/centos
我们看看这个容器1c5f134a28dd是不是继承上一个容器4814609ae6bb的数据?看下图,确实继承咯.
注意: 我说继承只是方便大家理解,实际上他们的关系是共享,容器2继承容器1,会拥有容器1的数据,相反往容器2添加数据也会影响容器1,他们之间的数据是一致性的!
九、DockerFile解析
9.1 DockerFile是什么?
DockerFile是用来构建Docker镜像的文件,是由一系列命令和参数构成的脚本.
构建三步骤: 编写DockerFile文件 -> docker build -> docker run
9.1 DockerFile保留字指令
FROM: FROM是Dockerfile里的第一条指令(必须是),后面跟有效的镜像名(如果该镜像你的本地仓库没有则会从远程仓库Pull取)。然后后面的其它指令FROM的镜像中执行。
MAINTAINER: 用于提供信息的指令,用于让作者提供本人的信息;不限制其出现的位置,但建议紧跟在FROM之后;
RUN: 运行命令,命令较长使可以使用\来换行。推荐使用上面数组的格式
CMD: CMD指定容器启动是执行的命令,每个Dockerfile只能有一条CMD命令,如果指定了多条,只有最后一条会被执行。如果你在启动容器的时候也指定的命令,那么会覆盖Dockerfile构建的镜像里面的CMD命令。
ENTRYPOINT: 和CMD类似都是配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。
USER: 指定运行容器时的用户名和UID,后续的RUN指令也会使用这里指定的用户。
EXPOSE: 设置Docker容器内部暴露的端口号,如果需要外部访问,还需要启动容器时增加-p或者-P参数进行分配。
ENV: 设置环境变量,可以在RUN之前使用,然后RUN命令时调用,容器启动时这些环境变量都会被指定
ADD: 将指定的<src>复制到容器文件系统中的<dest> 所有拷贝到container中的文件和文件夹权限为0755,uid和gid为0
VOLUME: 如果mountpoint路径下事先有文件存在,docker run命令会在卷挂载完成后将此前的文件复制到新挂载的卷中;
WORKDIR: 切换目录,为后续的RUN、CMD、ENTRYPOINT 指令配置工作目录。
ONBUILD : ONBUILD不能自我嵌套,且不会触发FROM和MAINTAINER指令;
ARG: ARG指定了一个变量在docker build的时候使用,可以使用--build-arg <varname>=<value>来指定参数的值,不过如果构建的时候不指定就会报错。
COPY: 用于从docker主机复制文件至正在创建的映像文件中;
1、FROM
解释:FROM是Dockerfile里的第一条指令(必须是),后面跟有效的镜像名(如果该镜像你的本地仓库没有则会从远程仓库Pull取)。然后后面的其它指令FROM的镜像中执行。
必须是第一个非注释行,用于指定所用到的基础镜像;
语法格式:
FROM <image>[:<tag>]
FROM <image>@<digest>
FROM busybox:latest
FROM centos:6.9
注意:尽量不要在一个dockerfile文件中使用多个FROM指令;
2、MAINTAINER
格式:MAINTAINER <name>
例如:MAINTANIER MageEdu Linux Operation and Maintance Institute <mage@magedu.com>
解释:用于提供信息的指令,用于让作者提供本人的信息;不限制其出现的位置,但建议紧跟在FROM之后;
3、RUN
用于指定docker build过程中要运行的命令,而不是docker run此dockerfile构建成的镜像时运行;
格式:RUN <command>或 RUN["executable", "param1", "param2"]
解释:运行命令,命令较长使可以使用\来换行。推荐使用上面数组的格式
语法格式:
RUN <command> 或
RUN ["<executeable>", "<param1>", "<param2>", ...]
RUN ["/bin/bash", "-c", "<executeable>", "<param1>", "<param2>", ...]
例如:RUN yum install iproute nginx && yum clean all
4、CMD
类似于RUN指令,用于运行程序;但二者运行的时间点不同;CMD在docker run时运行,而非docker build;
格式:
CMD ["executable","param1","param2"]
使用 exec 执行,推荐方式;
CMD command param1 param2
在 /bin/sh 中执行,提供给需要交互的应用;
CMD ["param1","param2"]
为ENTRYPOINT指令指定的程序提供默认参数;
解释:
CMD指定容器启动是执行的命令,每个Dockerfile只能有一条CMD命令,如果指定了多条,只有最后一条会被执行。如果你在启动容器的时候也指定的命令,那么会覆盖Dockerfile构建的镜像里面的CMD命令。
CMD指令的首要目的在于为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束;不过,CMD指令指定的程序可被docker run命令行参数中指定要运行的程序所覆盖
注意:如果dockerfile中存在多个CMD指令,仅最后一个生效;
CMD ["/usr/sbin/httpd", "-c","/etc/httpd/conf/httpd.conf"]
5、ENTRYPOINT
格式:
ENTRYPOINT ["executable", "param1","param2"]
ENTRYPOINT command param1 param2
(shell中执行)。
例如:CMD ["-c"] ENTRYPOINT ["top", "-b"]
类似于CMD指令,但其不会被docker run的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给ENTRYPOINT指令指定的程序;但是,如果运行docker run时使用了–entrypoint选项,此选项的参数可当作要运行的程序覆盖ENTRYPOINT指令指定的程序;
解释:和CMD类似都是配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。
每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。
ENTRYPOINT没有CMD的可替换特性,也就是你启动容器的时候增加运行的命令不会覆盖ENTRYPOINT指定的命令。
所以生产实践中我们可以同时使用ENTRYPOINT和CMD, 例如:
ENTRYPOINT ["/usr/bin/rethinkdb"]
CMD ["--help"]
6、USER
指定运行镜像时,或运行Dockerfile文件中的任何RUN/CMD/ENTRYPOINT指令指定的程序时的用户名或UID;
格式:USER <UID>|<Username>
解释:指定运行容器时的用户名和UID,后续的RUN指令也会使用这里指定的用户。
注意:应该使用/etc/passwd文件存在的用户的UID,否则,docker run可能会出错;
7、EXPOSE
用于为容器指定要暴露的端口;
格式:EXPOSE<port> [<port>...] <prot>为tcp或udp二者之一,默认为tcp;
例如: EXPOSE 11211/tcp 11211/udp
解释:设置Docker容器内部暴露的端口号,如果需要外部访问,还需要启动容器时增加-p或者-P参数进行分配。
8、ENV
解释:设置环境变量,可以在RUN之前使用,然后RUN命令时调用,容器启动时这些环境变量都会被指定
定义环境变量,此些变量可被当前dockerfile文件中的其它指令所调用,调用格式为variablename或variable_name或variablename或{variable_name};
ENV定义的环境变量在镜像运行的整个过程中一直存在,因此,可以使用inspect命令查看,甚至也可以在docker run启动此镜像时,使用–env选项来修改指定变量的值;
格式:ENV<key> <value> 一次定义一个变量
ENV <key>=<value> ... 一次可定义多个变量 ,如果<value>中有空白字符,要使用\字符进行转义或加引号;
ENV myName="Obama Clark" myDog=Hello\ Dog \ myCat=Garfield
等同于:
ENV myName Obama Clark
ENV myDog Hello Dog
ENV myCat Garfield
解释:设置环境变量,可以在RUN之前使用,然后RUN命令时调用,容器启动时这些环境变量都会被指定
9、ADD:
类似于COPY指令,额外还支持复制TAR文件,以及URL路径;
格式:
ADD <src>... <dest>
ADD ["<src>",... "<dest>"]
解释:将指定的< src>复制到容器文件系统中的< dest> 所有拷贝到container中的文件和文件夹权限为0755,uid和gid为0
如果文件是可识别的压缩格式,则docker会帮忙解压缩
示例: ADD haproxy.cfg /etc/haproxy/haproxy.cfg ADD logstash_*.cnf /etc/logstash/ ADD http://www.magedu.com/download/nginx/conf/nginx.conf /etc/nginx/ 注意:以URL格式指定的源文件,下载完成后其目标文件的权限为600; 注意: < src>必须是build上下文中的路径,因此,不能使用类似“…/some_dir/some_file”类的路径; 如果< src>是URL,且< dest>不以/结尾,则< src>指定的文件将被下载并直接被创建为< dest>;如果< dest>以/结尾,则URL指定的文件将被下载至< dest>中,并保留原名; 如果< src>是一个host本地的文件系统上的tar格式的文件,它将被展开为一个目录,其行为类似于tar -x命令;但是,如果通过URL下载到的文件是tar格式的,是不会自动进行展开操作的; < src>如果是目录,递归复制会自动行;如果有多个< src>,包括在< src>上使用了通配符这种情形,此时< dest>必须是目录,而且必须得以/结尾; < dest>如果事先不存在,它将被自动创建,包括其父目录;
10、VOLUME
用于目标镜像文件中创建一个挂载点目录,用于挂载主机上的卷或其它容器的卷;
格式:VOLUME ["/data"] VOLUME ["<mountpoint>", ...]
解释:可以将本地文件夹或者其他container的文件夹挂载到container中。
注意:如果mountpoint路径下事先有文件存在,docker run命令会在卷挂载完成后将此前的文件复制到新挂载的卷中;
11、WORKDIR
用于为Dockerfile中所有的RUN/CMD/ENTRYPOINT/COPY/ADD指令指定工作目录;
格式:WORKDIR/path/to/workdir
解释:切换目录,为后续的RUN、CMD、ENTRYPOINT 指令配置工作目录。
可以多次切换(相当于cd命令),
也可以使用多个WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
则最终路径为 /a/b/c。
WORKDIR /var/log
WORKDIR $STATEPATH
注意:WORDIR可出现多次,也可使用相对路径,此时表示相对于前一个WORKDIR指令指定的路径;WORKDIR还可以调用由ENV定义的环境变量的值;
12、ONBUILD :定义触发器
ONBUILD 指定的命令在构建镜像时并不执行,而是在它的子镜像中执行
语法格式
ONBUILD <INSTRUCTION>
例如:ONBUILD ADD my.cnf /etc/mysql/my.cnf
当前dockerfile构建出的镜像被用作基础镜像去构建其它镜像时,ONBUILD指令指定的操作才会被执行;
注意:ONBUILD不能自我嵌套,且不会触发FROM和MAINTAINER指令;
13、ARG
格式:ARG<name>[=<default value>]
解释:ARG指定了一个变量在docker build的时候使用,可以使用–build-arg =来指定参数的值,不过如果构建的时候不指定就会报错。
14、COPY指令
用于从docker主机复制文件至正在创建的映像文件中;
语法格式:
COPY <src> ... <dest>
COPY ["<src>",... "<dest>"] (文件名中有空白字符时使用此种格式)
< src>:要复制的源文件或目录,支持使用通配符;
< dest>:目标路径,正在创建的镜像文件的文件系统路径;建立使用绝对路径,否则,则相对于WORKDIR而言;
所有新复制生成的目录文件的UID和GID均为0;
例如:
COPY server.xml /etc/tomcat/server.xml
COPY *.conf /etc/httpd/conf.d/
注意:
< src>必须是build上下文中的路径,因此,不能使用类似“…/some_dir/some_file”类的路径;
< src>如果是目录,递归复制会自动行;如果有多个< src>,包括在< src>上使用了通配符这种情形,此时< dest>必须是目录,而且必须得以/结尾;
< dest>如果事先不存在,它将被自动创建,包括其父目录;
十、Docker小结
一张图,大家看一下
10.1 本地镜像发布到阿里云
step1. 登录阿里云账号,创建明命名空间
step 2 创建镜像仓库
step 3 选择管理
step 4 根据操作指南动手
我这边弄个tomcat
我们去阿里云看看,我们的镜像在阿里云能不能看到(我之前设置的私有的,后来换成公开的)