Docker是一个开源的容器引擎,它有助于更快地交付应用。Docker可将应用程序和基础设施层隔离,并且能将基础设施当作程序一样进行管理。
使用Docker可更快地打包、测试以及部署应用程序,并可以缩短从编写到部署运行代码的周期。
docker是一个用来装应用的容器,就像杯子可以装水,笔筒可以放笔,书包可以放书,可以把hello word放在docker中,可以把网站放入docker中,可以把任何想得到的程序放在docker中.
没有集装箱之前运输货物,东西零散容易丢失,有了集装箱之后货物不容易丢失,我们可以把货物想象成程序,目前我们要把程序部署到一台新的机器上,可能会启动不起来,比如少一些配置文件什么的或者少了什么数据,有了docker的集装箱可以保证我们的程序不管运行在哪不会缺东西.
运输方式
docker运输东西有一个超级码头,任何地方需要货物都由鲸鱼先送到超级码头,然后再由鲸鱼从超级码头把货物送到目的地去.对应的技术来说,比如我们要把台式机的应用部署到笔记本上,我们可能选择用QQ发过去或者用U盘拷过去,docker就标准化了这个过程,我们只需在台式机上执行一个docker命令,把鲸鱼派过来,把程序送到超级码头去,再在笔记本上执行一个docker命令,然后由鲸鱼把程序从超级码头送到笔记本上去.
存储方式
当我们把程序存储到笔记本上时,我们需要一个目录,且我们要记住这个目录,因为下次我们可能还要修改,有了docker之后我们就不用记住了程序在哪里了,我们使用的时候只需要一条命令就行了.
API接口
docker提供了一系列rest api的接口,包含了对docker也就是对我们的应用的一个启动停止查看删除等等,如当我们要启动tomcat时我们要执行startup命令,当我们要停止时要执行shutdown命令,如果不是tomcat,我们可能还需要一些别的命令.有了docker我们记docker的命令就可以对其进行操作.
我们在使用虚拟机时有自己的cpu,硬盘,内存,完全感觉不到外面主机的存在,docker也差不多,不过它更轻量,我们创建虚拟机可能要几分钟,但是docker只需要一秒.最底层的技术时linux一种内核的限制机制,叫做LXC,LXC是一种轻量级的容器虚拟化技术.最大效率的隔离了进程和资源.通过cgroup,namespace等限制,隔离进程组所使用的物理资源,比如CPU,MEMORY等等
开发:我本地没问题.
运维:服务器没问题. 这个问题就变成了皮球.
如果一个应用要正常的启动起来需要什么?比如java web应用.
需要一个操作系统,操作系统之上要jdk,tomcat,我们的代码,配置文件.
操作系统的改变可能会导致我们的应用开不起来,比如我们调用了某些系统命令.
jdk版本也可能导致程序的运行失败.比如class文件需要1.7编译,我们装了个1.6的jdk.
tomcat版本也能导致失败,比如旧的版本一些配置在新版本中不再支持.
代码的话就比如应用了C盘,D盘的一个文件,或者是用了系统的一些环境编码.
配置的话我们可能少了某个配置文件等等.
下面docker来了,它把操作系统,jdk,tomcat,代码,配置全部放到集装箱里.再打包放到鲸鱼(Docker)上,由鲸鱼给我们送到服务器上,在我的机器上怎么运行,在别的机器上也怎么运行.不会有任何的问题.一句话就是docker解决了运行环境不一致所带来的问题.
当与其他人公用服务器的时候,莫名其妙发现自己的程序挂了,一查原因要不是内存不够了,要不是硬盘满了,还有就是发现某个服务变慢了,甚至敲终端都比较卡,但是linux本身就是一个多用户的操作系统本身就可以供多个用户使用,docker的隔离性可以解决这个问题,就算别人的程序还是死循环疯狂吃CPU,还是封装疯狂打日志把硬盘占满,还是内存泄漏,把内存占满,都不会导致我们的程序运行错误.因为docker在启动的时候就限定好了,它最大使用的CPU硬盘,如果超过了,就会杀掉对应进程.
大部分系统业务量并不是每天都比较平均的,特别是一些电商系统,每天总有那么几天业务量是平时的几倍甚至几十倍,如果按双11的规模去准备服务器那么对于平时的规模来说又是极大的浪费,所以就在节日前临时扩展机器,过完节再把多余的节点下线,这就给运维带来了非常大的工作量,一到过节就在各个机器上部署各种各样的服务,我们启动程序需要java,tocmat等等,并且还可能起不来还要调试,这是非常恶心的工作,有了docker一切都变得美好了,只要点一下服务器就可以从10台变成100台甚至1000,1W台.都是分分钟的事情.
为什么会这么快呢?都是用标准的方式把我们的程序运过来,下载过来,再用标准的方式把它运行起来,就可以做到只要在每台机器上都执行一两条命令,就可以让程序正常跑起来,并且不用担心有问题.
Docker让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,便可以实现虚拟化。Docker改变了虚拟化的方式,使开发者可以直接将自己的成果放入Docker中进行管理。
守护进程,客户端,镜像,容器,仓库,Registry
镜像就是上面说的集装箱,仓库就是超级码头,容器就是我们运行程序的地方.docker运行程序的过程就是去仓库把镜像拉到本地,然后用一条命令把镜像运行起来变成容器.
安装了Docker程序的机器(Docker直接安装在操作系统之上);
是一个运行在宿主机(DOCKER-HOST)的后台进程。可通过 Docker客户端与之通信。
Docker客户端是Docker的用户界面,它可以接受用户命令和配置标识,并与Docker daemon通信。 连接docker主机进行操作
软件打包好的镜像;放在docker仓库中;
Docker镜像是一个只读模板,它包含创建 Docker容器的说明。它和系统安装光盘有点像,使用系统安装光盘可以安装系统,同理,使用Docker镜像可以运行Docker镜像中的程序。Docker镜像中包含了运行环境和配置,所以Docker可以简化部署多种应用实例工作。
从本质上来说镜像就是一系列文件,可以包括我们应用程序的文件,也可以包括我们应用的运行环境的文件,既然是文件,那么是以什么样的格式在本地保存的呢?
说到存储格式,就要提到linux的一个存储技术,叫做联合文件系统,是一种分层的文件系统,可以将不同的目录挂到同一个虚拟文件系统下.
比如test1下有三个文件夹,test2下有两个文件夹,还有一个readme文件.联合文件系统就是可以在一个文件夹(test)中看到多个文件夹(test1,test2)中的内容.
通过这种方式可以实现文件的分层,test1可以把它看作第一层,test2可以把它看作第二层,每一层有每一层自己的文件,docker就是利用了这种分层的概念实现了镜像存储.
上图就是镜像的存储格式,这张图是分层的,最下面一层,上面也是一层层的好像集装箱罗列在一起.这就是镜像最直观的存储方式.下面是操作系统的引导,上面是linux操作系统,再上面是一些相关的软件,如果是我们自己的程序,就可以是tomcat,jdk,再往上是应用代码,每一层是我们自己都可以控制得,最上面一层先忽略不看,因为这是和容器有关的.注意一点,docker镜像系统的每一层都是只读的,然后把每一层加载完成之后这些文件都会被看成是同一个目录,相当于只有一个文件系统.docker的这种文件系统被称之为镜像.
镜像启动后的实例称为一个容器;容器是独立运行的一个或一组应用
容器是镜像的可运行实例。镜像和容器的关系有点类似于面向对象中,类和对象的关系.
为了便于理解,大家可以把容器想象成虚拟机,每个虚拟机都有自己的文件系统,可以把上图整个一部分看成是文件系统,与虚拟机系统的区别是这里面的文件系统是一层一层的,并且最下面的n层都是只读的,只有上面一层是可写的.为什么要有可写的这层呢?大家的程序运行起来,势必会要写一些日志,写一些文件,或者对系统的某一些文件做一些修改,所以容器在最上面一层创建了可读可写的文件系统.
在程序的运行过程中,如果要写镜像文件时,因为镜像的每一层都是只读的,它会把文件的每一层拷到文件的最上层,然后再对它进行修改,修改之后,当我们的应用读一个文件时会从顶层进行查找,如果没有才会找下一层.
由于容器的最上一层是可以修改的,镜像是不能修改的,这样就能保证镜像可以生成多个容器独立运行,没有任何干扰.
用来保存各种打包好的软件镜像;
Docker Registry是一个集中存储与分发镜像的服务。构建完 Docker镜像后,就可在当前宿主机上运行。但如果想要在其他机器上运行这个镜像,就需要手动复制。此时可借助Docker Registry来避免镜像的手动复制。
我们要先把我们的镜像传到docker仓库中,再由目的地把docker仓库拉过去,这就完成了这样的一次传输过程.
一个Docker Registry可包含多个Docker仓库,每个仓库可包含多个镜像标签,每个标签对应一个Docker镜像。这跟Maven的仓库有点类似,如果把Docker Registry比作Maven仓库的话,那么Docker仓库就可理解为某jar包的路径,而镜像标签则可理解为jar包的版本号。
Docker Registry可分为公有Docker Registry和私有Docker Registry。官方提供的默认为: hub.docker.com
, 但是非常慢.
可通过修改的方式来改为国内一些公司提供的。具体操作见后面讲解。
国内仓库:
网易蜂巢: https://c.163yun.com/hub#/m/home/
阿里:
Docker 要求 CentOS 系统的内核版本高于 3.10, 通过如下命令查看内核版本
uname -r
保证 yum
包为最新
yum update
卸载旧版本(如果安装过旧版本的话)
yum remove docker docker-client docker-client-latest docker-common \
docker-latest docker-latest-logrotate docker-logrotate docker-engine
#说明若不换行后面的\则不需要
安装依赖设置yum仓库
#安装依赖
yum install -y yum-utils device-mapper-persistent-data lvm2
##设置yum仓库源
yum-config-manager --add-repo \
https://download.docker.com/linux/centos/docker-ce.repo #官网地址,可切换为国内提供的地址
#阿里提供的地址
#http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum list docker-ce --showduplicates | sort -r
安装docker
# 默认安装,不指定版本
yum install docker-ce docker-ce-cli containerd.io
#执行这个命令要耐心等待,中间要输入两次y,当然你也可以在yum命令后面直接跟-y跳过询问
# 指定版本安装
yum install docker-ce-17.12.0.ce
启动并加入开机启动
systemctl start docker #启动
systemctl enable docker #设置开机启动
docker version
修改配置仓库
Docker默认是从国外的网站拉取镜像的,所以一般而言速度会比较慢。所以建议配置国内一些公司提供的仓库。
以配置阿里镜像加速器为例
注册阿里云账号
登录到控制台,找到镜像加速器
按照官方指定的方式操作,修改仓库地址的配置文件
重新加载配置文件,并重启docker
systemctl daemon-reload
systemctl restart docker
操作完成后,通过如下命令验证仓库地址是否修改成功
docker info #查看Registry Mirrors指定的地址
https://docs.docker.com/install/linux/docker-ce/ubuntu/
docker search 镜像名
#执行该命令,docker会在指定的仓库中(若未配置,则默认为官网Docker Hub)中搜索含有该镜像名的关键字的仓库
搜索列表包含五列,含义如下:
- NAME: 镜像仓库名称。
- DESCRIPTION: 镜像仓库描述。
- STARS:镜像仓库收藏数,表示该镜像仓库的受欢迎程度,类似于 GitHub的 stars0
- OFFICAL: 表示是否为官方仓库,该列标记为[0K]的镜像均由各软件的官方项目组创建和维护。
- AUTOMATED:表示是否是自动构建的镜像仓库。
docker pull [options] NAME[:TAG]
#说明 其中[]表示该内容可选,name是拉取镜像的名称,:TAG为空表明是latest,如果选择表明是指定版本的.
#options是拉取的一些参数.如拉取地址
#如拉取tomcat
docker pull tomcat:7 # 下载tomcat7的镜像到本地
docker images #列出已下载的镜像
列出的列表含义如下:
- REPOSITORY:镜像所属仓库名称。
- TAG:镜像标签。默认是 latest,表示最新。
- IMAGE ID:镜像 ID,表示镜像唯一标识。
- CREATED:镜像创建时间。
- SIZE: 镜像大小。
docker rmi 镜像名[:tag] #删除指定镜像
docker create [OPTIONS] IMAGE [COMMAND] [ARG...] #参考新建并启动容器
docker run [OPTIONS] IMAGE [COMMAND] [ARG...] #交互式启动或后台启动,参考新建并启动容器
docker start 容器id/容器名 #启动已停止的容器
docker restart 容器id/容器名
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
#示例1 以后台模式启动一个镜像为nginx:latest的容器,并命名为mynginx
docker run -d --name mynginx nginx:latest
#示例2 以交互模式启动一个镜像为nginx:latest的容器bash交互终端,并命名为mynginx
docker run -it --name mynginx nginx:latest /bin/bash
OPTIONS常用参数说明:
-d: 后台运行容器,并返回容器ID;
-i: 以交互模式运行容器,通常与 -t 同时使用;
-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
-p: 指定端口映射,格式为:主机(宿主)端口:容器端口 ;
-P: 随机端口映射,容器内部端口随机映射到主机的端口 ;
–name="nginx-lb
": 为容器指定一个名称;
其他参考:docker run 参数说明
注意:使用docker run命令创建容器时,会先检查本地是否存在指定镜像。如果本地不存在该名称的镜像, Docker就会自动从Docker Hub(默认)下载镜像并启动一个 Docker容器。
docker ps
docker ps -a #列出所有容器(包括已停止的容器),
列出的列表含义如下:
- CONTAINER_ID:表示容器 ID。
- IMAGE:表示镜像名称。
- COMMAND:表示启动容器时运行的命令。
- CREATED:表示容器的创建时间。
- STATUS:表示容器运行的状态。UP表示运行中, Exited表示已停止。
- PORTS:表示容器对外的端口号。
- NAMES:表示容器名称。该名称默认由 Docker自动生成,也可使用 docker run命令的–name选项自行指定。
docker stop 容器id/容器名
docker kill 容器id/容器名 #杀死容器
docker logs -f 容器id/容器名
docker exec -it 容器id /bin/bash #进入一个正在运行的docker容器
exit
docker rm 容器id/容器名 #删除已停止的容器
docker rm -f 容器id/容器名 #删除正在运行的容器,可使用-f参数
docker rm $(docker ps -a -q) #删除所有容器
# 一共有三种形式进行端口映射
docker -p ip:hostPort:containerPort # 映射指定地址的主机端口到容器端口
# 例如:docker -p 127.0.0.1:3306:3306 映射本机3306端口到容器的3306端口
docker -p ip::containerPort # 映射指定地址的任意可用端口到容器端口
# 例如:docker -p 127.0.0.1::3306 映射本机的随机可用端口到容器3306端口
docer -p hostPort:containerPort # 映射本机的指定端口到容器的指定端口
# 例如:docker -p 3306:3306 # 映射本机的3306端口到容器的3306端口
docker -v /home/data:/opt/data # 这里/home/data 指的是宿主机的目录地址,后者则是容器的目录地址
Dockerfile
是一个文本格式的配置文件,用户可以使用Dockerfile
快速创建自定义的镜像。
Dockerfile
中包括FROM、MAINTAINER、RUN、CMD、EXPOSE、ENV、ADD、COPY、ENTRYPOINT、VOLUME、USER、WORKDIR、ONBUILD等13个指令。
#格式为:俩种格式
FROM image
FROM image:tag
#Dockerfile中第一条指令必须是FROM指令,且在同一个Dockerfile中创建多个镜像时,可以使用多个FROM指令。
#格式为:
MAINTAINER user_name user_email #指定维护者姓名,邮箱
#格式为:俩种格式
RUN command
#表示在shell终端中(当前终端)运行命令,/bin/sh -c command
#例如:/bin/sh -c "echo hello";
RUN ["EXECUTABLE","PARAM1","PARAM2".....]
#使用exec执行,指定其他运行终端使用RUN["/bin/sh", "-c", "echo hello"]
每条RUN指令在当前的镜像基础上执行指令,并提交为新的镜像。
#支持三种格式:
CMD ["executable","param1","param2"],使用exec执行,这是推荐的方式。
CMD command param1 param2 在/bin/sh中执行。
CMD ["param1","param2"] 提供给ENTERYPOINT的默认参数。
#CMD用于指定容器启动时执行的命令,每个Dockerfile只能有一个CMD命令,多个CMD命令只执行最后一个。若容器启动时指定了运行的命令,则会覆盖掉CMD中指定的命令。
#格式为:
EXPOSE port [port2,port3,...]
#例如EXPOSE 80这条指令告诉Docker服务器暴露80端口,供容器外部连接使用。
#在启动容器的使用使用-P,Docker会自动分配一个端口和转发指定的端口,使用-p可以具体指定使用哪个本地的端口来映射对外开放的端口。
#格式为:
EVN key value
#用于指定环境变量,这些环境变量,后续可以被RUN指令使用,容器运行起来之后,也可以在容器中获取这些环境变量。
#例如
ENV word hello
RUN echo $word
ADD src dest
#将复制指定本地目录中的文件到容器中的dest中,src可以是是一个绝对路径,也可以是一个URL或一个tar文件,tar文件会自动解压为目录
COPY src desc
#复制本地主机src目录或文件到容器的desc目录,desc不存在时会自动创建。
#格式有两种:
ENTRYPOINT ["executable","param1","param2"]
ENTRYPOINT command param1,param2 会在shell中执行。
#用于配置容器启动后执行的命令,这些命令不能被docker run提供的参数覆盖。和CMD一样,每个Dockerfile中只能有一个ENTRYPOINT,当有多个时最后一个生效
VOLUME ["/data"]
#作用是创建在本地主机或其他容器可以挂载的数据卷,用来存放数据
USER username
#指定容器运行时的用户名或UID,后续的RUN也会使用指定的用户。要临时使用管理员权限可以使用sudo。在USER命令之前可以使用RUN命令创建需要的用户。
#例如:RUN groupadd -r docker && useradd -r -g docker docker
WORKDIR /path
#为后续的RUN CMD ENTRYPOINT指定配置工作目录,可以使用多个WORKDIR指令,若后续指令用得是相对路径,则会基于之前的命令指定路径
ONBUILD [INSTRUCTION]
#该配置指定当所创建的镜像作为其他新建镜像的基础镜像时所执行的指令。
#例如下面的Dockerfile创建了镜像A:
ONBUILD ADD . /app
ONBUILD RUN python app.py
#则基于镜像A创建新的镜像时,新的Dockerfile中使用from A 指定基镜像时,会自动执行ONBBUILD指令内容,等价于在新的要构建镜像的Dockerfile中增加了两条指令:
FROM A
ADD ./app
RUN python app.py
创建好Dockerfile
之后,通过docker build命令来创建镜像,该命令首先会上传Dockerfile
文件给Docker服务器端,服务器端将逐行执行Dockerfile
中定义的指令。
通常建议放置Dockerfile
的目录为空目录。另外可以在目录下创建.dockerignore
文件,让Docker忽略路径下的文件和目录,这一点与Git中的配置很相似。
#通过 -t 指定镜像的标签信息,例如:
docker build -t regenzm/first_image .
##"."指定的是Dockerfile所在的路径
Dockerfile
文件分为四个部分:
#在Dockerfile中使用#完成一行的注解
#第一行必须制定基础镜像
FROM centos
#MAINTAINER 指定维护者信息
MAINTAINER your_name your_email
#RUN、ADD、ENV、EXPOSE等
#如使用yum安装mysql
RUN yum -qqy install mysql
#CMD 等指令
修改宿主机配置文件
vi /lib/systemd/system/docker.service #通过vim打开docker的配置文件
找到ExecStart
开头的这一行,其内容为
ExecStart=/usr/bin/dockerd-current \
将其替换为
#此处开放端口为999,可根据自己情况来设定,默认端口是2375,外网建议不要使用默认端口"2375"
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:999 -H unix://var/run/docker.sock \
重启docker
systemctl daemon-reload && systemctl restart docker
防火墙开放端口(若防火墙未开启,则无需该操作)
firewall-cmd --zone=public --add-port=999/tcp --permanent
表示防火墙未开启
内部验证是否成功
#查看端口是否开启
netstat -nptl
#直接curl看是否生效
curl http://127.0.0.1:999/info
通过外部网络访问测试
#此处ip地址为服务器的ip
http://ip地址:999/version
若返回一个json格式的文件,则表示开放成功。
通过docker
拉取tomcat
镜像
以交互的方式启动tomcat
容器,并进入容器
docker run -it --name webdemo -p 80:8080 tomcat /bin/bash
此时已经进入到容器内,切换目录到tomcat
下的webapps
目录下
web
应用打包成war
,拷贝到该目录下即可
从主机复制到容器的指定路径 sudo docker cp host_path containerID:container_path
从容器的指定路径复制到主机 sudo docker cp containerID:container_path host_path
# 若是root用户登录,则sudo可省略,冒号后边不能有空格
#如
docker cp /mnt/webdemo.war a2f2091a661fa51e02c0be54f252fc46fc604932526b17038ccc267affcef12c:/usr/local/tomcat/webapps
启动tomcat
即可访问
通过Dockerfile
来制作镜像,每一步的执行操作是什么。
新建Dockerfile
的文件,编辑文件内容告诉每一步的操作;
将web
应用和Dockerfile
文件放在同一目录下;
构建镜像
docker build -t 镜像名:版本号. # 根据当前目录构建镜像,-t表示给镜像指定一个tag
pom.xml
文件<properties>
<docker.image.prefix>docker-demodocker.image.prefix>
properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
<plugin>
<groupId>com.spotifygroupId>
<artifactId>docker-maven-pluginartifactId>
<version>1.0.0version>
<configuration>
<imageName>${docker.image.prefix}/${project.artifactId}imageName>
<dockerDirectory>${project.basedir}/src/main/dockerdockerDirectory>
<resources>
<resource>
<targetPath>/targetPath>
<directory>${project.build.directory}directory>
<include>${project.build.finalName}.jarinclude>
resource>
resources>
configuration>
plugin>
<plugin>
<artifactId>maven-antrun-pluginartifactId>
<executions>
<execution>
<phase>packagephase>
<configuration>
<tasks>
<copy todir="src/main/docker" file="target/${project.artifactId}-${project.version}.${project.packaging}">copy>
tasks>
configuration>
<goals>
<goal>rungoal>
goals>
execution>
executions>
plugin>
plugins>
build>
src/main
目录下创建 docker
目录与 Dockerfile
文件# 指定基础镜像 这里springboot项目运行只需要java jdk环境即可
FROM java:latest
# 维护者信息
MAINTAINER zq
# 将本地的可执行文件拷贝到Docker容器中的根目录下
COPY app.sh /
#给app.sh赋予可执行权限
RUN chmod +x /app.sh
# 重命名
ADD *.jar app.jar
# 对外暴漏的端口号
EXPOSE 9100
# 运行
ENTRYPOINT ["/app.sh"] # 方式一
#ENTRYPOINT ["java", "-jar", "app.jar"] # 方式二
app.sh
#!/bin/bash
java -jar app.jar
配置运行
参考:idea使用Docker部署项目到服务器的全过程
参考:
Docker入门
idea使用Docker部署项目到服务器的全过程
main目录下创建
docker目录与
Dockerfile` 文件
# 指定基础镜像 这里springboot项目运行只需要java jdk环境即可
FROM java:latest
# 维护者信息
MAINTAINER zq
# 将本地的可执行文件拷贝到Docker容器中的根目录下
COPY app.sh /
#给app.sh赋予可执行权限
RUN chmod +x /app.sh
# 重命名
ADD *.jar app.jar
# 对外暴漏的端口号
EXPOSE 9100
# 运行
ENTRYPOINT ["/app.sh"] # 方式一
#ENTRYPOINT ["java", "-jar", "app.jar"] # 方式二
app.sh
#!/bin/bash
java -jar app.jar
配置运行
参考:idea使用Docker部署项目到服务器的全过程
参考:
Docker入门
idea使用Docker部署项目到服务器的全过程