环境篇:Docker
Docker 是什么?
Docker 是一个开源的应用容器引擎,基于Go语言并遵从Apache协议的开源,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。
如果没有Docker
环境和配置变动,导致项目等不能简单的部署成功,我们将需要的配置、系统、数据等等整体打包成我们需要的镜像,简单启动就可以了,
Securely build and share any application, anywhere一次构建,处处运行。
- 虚拟机和容器化的区别?
-
虚拟机:整套安装环境的一种解决方案,它可以在一种操作系统里面运行另一个操作系统,比如在Windows系统里面运行Linux系统。应用程序对此没有感知,因为虚拟机看上去就和真实的操作系统一模一样,能够使应用程序,操作系统和硬件三者之间的逻辑不变,而对于底层系统来说,虚拟机就是一个普通文件,不需要了就删掉。
-
虚拟机占用的资源多、步骤多,启动是分钟级的太慢。
-
容器化技术:因为如上的问题,Linux发展出了另一种虚拟化技术,Linux容器(Linux Containers缩写LXC)。Linux容器不是模拟一个完整的操作系统,而是对程序进行隔离。有了容器,就可以将软件运行所需要的所有资源打包到一个隔离的容器中,容器和虚拟机不同,不需要捆绑一整套的操作系统,只需要软件工作所需要的库资源和设置。系统因此而变得高效轻量并保证部署在任何环境中的软件都能始终如一的运行。
-
1 Docker架构
- Docker 包括三个基本概念:
- 镜像(Image):Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统。
- 容器(Container):镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
- 仓库(Repository):仓库可看着一个代码控制中心,用来保存镜像。
Docker | 面向对象 |
---|---|
镜像 | 类 |
容器 | 对象 |
概念 | 说明 |
---|---|
Docker 镜像(Images) | Docker 镜像是用于创建 Docker 容器的模板,比如 Ubuntu 系统。 |
Docker 容器(Container) | 容器是独立运行的一个或一组应用,是镜像运行时的实体。 |
Docker 客户端(Client) | Docker 客户端通过命令行或者其他工具使用 Docker SDK (https://docs.docker.com/develop/sdk/) 与 Docker 的守护进程通信。 |
Docker 主机(Host) | 一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。 |
Docker Registry | Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub(https://hub.docker.com) 提供了庞大的镜像集合供使用。一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。 |
Docker Machine | Docker Machine是一个简化Docker安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker,比如VirtualBox、 Digital Ocean、Microsoft Azure。 |
2 Docker安装
- 以centos7以上为例。(安装2019.03版本)
- 删除老版本
yum -y remove docker
docker-client
docker-client-latest
docker-common
docker-latest
docker-logrotate
docker-latest-logrotate
docker-logrotate
docker-engine
yum-utils
device-mapper-persistent-data
lvm2
- 安装需要的软件包
#更新yum
yum -y update
yum install -y conntrack ipvsadm ipset jq sysstat curl iptables libseccomp
yum install -y yum-utils device-mapper-persistent-data lvm2
- 设置稳定储存库
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
- 更新yum软件包索引
yum makecache fast
- 安装的Docker Engine-Community和containerd
#指定版本安装
yum install -y docker-ce-18.09.0 docker-ce-cli-18.09.0 containerd.io
#最新版本安装
yum -y install docker-ce docker-ce-cli containerd.io
- 启动
systemctl start docker
- 设置开机启动
systemctl enable docker
- 测试
#版本
docker version
- 配置阿里云镜像加速
- 访问阿里云镜像加速器网页:https://account.aliyun.com/login/login.htm?oauth_callback=https%3A%2F%2Fcr.console.aliyun.com%2F
设置密码尽量简单如:docker123
- 如果觉得不方便可以使用网易云加速,地址更改如下
#1
mkdir -p /etc/docker
#2
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["http://hub-mirror.c.163.com"]
}
EOF
#3
systemctl daemon-reload
#4
systemctl restart docker
- hello-world镜像
docker run hello-world
3 Docker 命令
3.1 帮助命令
docker help
3.2 查看本地镜像
docker images
-a:显示所有的镜像
-q:仅显示id
REPOSITORY | 镜像仓库源 |
---|---|
TAG | 镜像标签 |
IMAGE ID | 镜像ID |
CREATED | 镜像创建时间 |
SIZE | 镜像大小 |
同一个REPOSITORY(仓库源)可以有多个TAG,代表这个仓库源的不同版本,使用REPOSITORY:TAG来定义不同的镜像。
如果不指定一个镜像的版本标签,例如:使用hello-world,docker将默认使用hello-world:latest镜像
3.3 查询镜像
docker search 需要的镜像
3.4 下载镜像
docker pull 需要的镜像:需要的版本tag
3.5 删除镜像
#删除单个
docker rmi -f 镜像ID
#删除多个
docker rmi -f 镜像名1:TAG 镜像名2:TAG
#删除全部
docker rmi -f ${docker images -qa}
3.6 查看容器
docker ps
-a:显示所有的容器
-l:显示最近一条容器
-n:显示最近几条容器
-q:仅显示id
3.7 新建启动停止容器
#新建容器并启动,如果没有镜像,会先去hubdocker上pull镜像
docker run 可选参数 镜像名(或ID)
#重启容器
docker restart 容器名(或ID)
#停止容器(普通<==>强制)
docker stop 容器名(或ID) <==> docker kill 容器名(或ID)
#启动之前创建的容器
docker start 容器名(或ID)
#删除之前创建的容器<==>批量
docker rm -f 容器ID <==> docker ps -aq | xargs docker rm
-d:守护式后台运行容器,并返回容器ID(如使用tomcat)
-v:数据卷,指定主机的某个目录为容器的某个目录(如使用tomcat-> /root/tomcat/:/usr/local/tomcat/webapps/)
-i:交互式运行容器,通常-t一起使用(如使用linux中的linux)
-t:为容器重新分配一个伪输入终端,通常与-i一起使用(如使用linux中的linux)
--name="新容器名字":为容器指定一个名称
-P:随机端口映射
-p:指定端口映射,有以下4种格式
ip:hostPort:containerPort
ip::containerPort
hostPort:containerPort
containerPort
3.7.1 守护式例子
#新建启动容器
docker run --name="tomcat1" -dp 8888:8080 tomcat:8.0.52
3.7.2 互交式例子
#1 新建启动容器,如下图中目录变更为容器ID
docker run --name='centos1' -it centos
#2 退出容器
exit -->容器停止退出
ctrl+p+q -->容器不停止退出(注意有先后顺序)
#3 进入一个运行的容器
docker exec -it 容器名(或ID) /bin/bash
3.8 提交容器
docker commit -a='作者' -m='修改内容' 容器名(或ID) 容器前缀/容器名:TAG号
- 使用上面守护式例子继续
#进入容器目录
docker exec -it tomcat1 /bin/bash
#替换index.jsp内容
cat > webapps/ROOT/index.jsp << EOF
Hello Tomcat
EOF
#提交容器
docker commit -a='Heaton' -m='my tomcat test' tomcat1 heaton/tomcat:0.0.1
#删除现有的运行容器
docker rm -f $(docker ps -q)
#运行之前自己构建的镜像容器
docker run --name="tomcat1" -dp 8888:8080 heaton/tomcat:0.0.1
3.9 上传镜像
- 选择阿里云或者hub,如下是阿里云的上传方式
#登录阿里云docker仓库,输入密码
dockerlogin --username=70xx@qq.com registry.cn-hangzhou.aliyuncs.com
#标记tag
docker tag b60d74c216b8 registry.cn-hangzhou.aliyuncs.com/docker-tzy/rep1:0.0.1
#上传
docker push registry.cn-hangzhou.aliyuncs.com/docker-tzy/rep1:0.0.1
4 容器数据卷
Docker容器产生的数据,如果不通过commit生成新的镜像,持久化,那么容器删除以后,数据就没有了。
为了能保存数据在docker中我们使用数据卷。
- 数据卷可以在容器之间共享或重用数据
- 卷中的更改可以直接生效
- 数据卷中的更改不会包含在镜像的更新中
- 数据卷的生命周期一直持续到没有容器使用它为止
docker inspect 容器ID --> 返回Docker对象的信息(查看挂载情况)
4.1 例1(命令-v)
#创建可读可写
docker run -it -v /my_root:/my_docker centos
#创建可读不可写(Read-only)
#docker run -it -v /my_root:/my_docker:ro centos
#进入绑定文件夹,主机建立新文件
touch root.txt
#进入绑定文件夹,容器修改文件
echo "docker add" > root.txt
#停止容器,主机修改文件
echo "root add" > root.txt
#在重新启动容器
docker start -i 34fe34e36ada
4.2 例2(DockerFile)
#创建Dockerfile文件 vim dockerFile,写入如下内容
#效果为docker run -it -v /my_root:/my_docker centos
FROM centos
VOLUME ["my_docker1","my_docker2"]
CMD echo "success"
CMD /bin/bash
#构建镜像
docker build -f /Dockerfile -t mybuild/centos:0.0.1 .
#运行,发现有2个容器卷
docker run -it mybuild/centos:0.0.1
如例1进行数据卷测试,发现数据共享
4.3 例3(volumes-from)
容器间数据共享
#运行容器1
docker run -it --name docker1 mybuild/centos:0.0.1
#运行容器2
docker run -it --name docker2 --volumes-from docker1 mybuild/centos:0.0.1
#运行容器3
docker run -it --name docker3 --volumes-from docker2 mybuild/centos:0.0.1
如例1进行数据卷测试
5 Dockerfile
Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。
Java | HelloWord.java | HelloWord.class |
---|---|---|
Docker | images | DockerFile |
-
基础注意点
- 每条保留字指令必须为大写字母且后面需要更至少一个参数
- 指令从上到下循序执行
#
为注释- 每条指令都会创建一个镜像层且对镜像进行提交
-
执行流程
- docker从基础镜像运行一个容器
- 执行一条指令并对容器做出修改
- 执行类似commit操作提交一个新的镜像层
- 再基于刚提交的镜像运行一个新容器
- 继续执行dockerfile中的下一条指令,循环制所有指令完成
-
保留字
FROM | 基础镜像,当前镜像是基于那个镜像的。 |
---|---|
MAINTAINER | 作者 邮箱。 |
RUN | 容器构建时需要运行的命令。 |
EXPOSE | 暴露端口号 启动容器的时候还需使用 –p 指定端口。 |
WORKDIR | 指定在创建容器后,终端默认登录后进来的工作目录,一个落脚点,默认根目录,通常绝对路径,CMD ENTRYPOINT 都会在这个目录下执行。 |
ENV | 构建镜像的过程中设置环境变量, 构建和运行时都有效可以使用$引用。 |
ADD | 将宿主机目录下的文件拷贝到镜像且会自动处理URL和 解压tar 压缩包。ADD 支持 URL 和 COPY后解压缩包。 |
COPY | 拷贝文件和目录到镜像中,将从构建上下文目录中<源路径>的文件/复制到新的一层镜像内<目标路径>的位置。一般都用ADD |
VOLUME | 容器数据卷, 数据保存和持久化。 |
USER | 指定该镜像由什么用户运行 不指定由root 运行。 |
CMD | 指定容器启动时要运行默认的命令,Dockerfile中可以有多个cmd , 但只有最后一个生效。CMD 会被docker run 之后的参数替换。 |
ENTERPOINT | 指定容器启动时要运行的命令。ENTERPOINT docker run 之后的参数会被当做参数传递给ENTRYPOINT , 之后形成新的命令组合,追加 |
ONBUILD | 触发器, 当构建一个被继承的dockerfile时运行命令, 父镜像在被子继承后的父镜像的onbuild 被触发。 |
- CMD 与 ENTERPOINT区别
- CMD
如 tomcat中,在Dockerfile最后有CMD ["catalina.sh","run"],意思为启动容器后执行tomcat启动命令,如果使用命令
docker run -it -p 8888:8080 tomcat:8.0.52 ls -l
,就会将ls -l这个查询指令通过参数传给CMD,这时容器运行就不会启动,而是查询目录。
- ENTERPOINT
如果是CMD ["ls","-l"]指令,我们需要在加入一个 -a 的参数,那么CMD将不能完成在构建镜像后增加参数,这个时候可以把指令改成ENTERPOINT ["ls","-l"] ,我们就可以在后面继续追加参数而不会替换原来的参数。
5.1 例1 拓展centos
- 自建centos
- 修改运行后路径
- 使之可以使用vim,ifconfig等命令
- 创建Dockerfile文件,加入如下内容
#继承自centos
FROM centos
#作者-邮箱
MAINTAINER Heaton
#创建环境变量mypath
ENV mypath /usr/local/src
#指定创建容器后终端路径
WORKDIR $mypath
#构建容器时运行命令
RUN yum -y install vim
RUN yum -y install net-tools
#暴露端口号
EXPOSE 80
#容器启动时要运行默认的命令
CMD echo "success"
CMD /bin/bash
- 构建镜像
docker build -f /root/Dockerfile -t heaton/centos:0.0.1 .
- 运行镜像
docker run -it heaton/centos:0.0.1
5.2 例2 触发器
- 创建Dockerfile1文件,加入如下内容
#继承自centos
FROM centos
ONBUILD RUN echo "father onbuild----------------------------->"
- 构建
docker build -f /root/Dockerfile1 -t heaton/father .
- 创建Dockerfile2文件,加入如下内容
#继承自heaton/father
FROM heaton/father
RUN echo "son------>success"
- 构建
docker build -f /root/Dockerfile2 -t heaton/son .