一 基本介绍
1. 什么是docker
Docker是一个开源的应用容器引擎,基于Go语言开发
Docker可以让开发者打包他们的应用与依赖到一个轻量级,可移植的容器中,然后发布到任何流星的Linux机器上,也可以实现虚拟化
容器完全使用沙箱机制,相互之间不会有任何接口且容器性能开销极低
传统虚拟机技术 VS Docker容器技术
特性 | 容器 | 虚拟机 |
---|---|---|
启动速度 | 快,秒级 | 慢,分钟级 |
性能 | 接近原生 | 较弱 |
内存代价 | 很小 | 较多 |
磁盘使用 | 小,MB甚至KB | 非常大,一般为GB |
运行密度 | 单机支持上百个甚至上千个 | 一台宿主机上十几个,最多几十个 |
资源利用率 | 高 | 低 |
总结:Docker技术可以让我们更加高效轻松的将任何应用在Linux服务器部署
2. docker架构
-
Docker daemon( Docker守护进程)
Docker daemon是一个运行在宿主机( DOCKER-HOST)的后台进程。可通过 Docker客户端与之通信 -
Client( Docker客户端)
Docker客户端是 Docker的用户界面,它可以接受用户命令和配置标识,并与 Docker daemon通信。图中, docker build等都是 Docker的相关命令 -
Images( Docker镜像)
Docker镜像是一个只读模板
,它包含创建 Docker容器的说明。它和系统安装光盘有点像,使用系统安装光盘可以安装系统,同理,使用Docker镜像可以运行 Docker镜像中的程序 -
Container(容器)
容器是镜像的可运行实例。镜像和容器的关系有点类似于面向对象中,类和对象的关系。可通过 Docker API或者 CLI命令来启停、移动、删除容器 -
Registry
Docker Registry是一个集中存储与分发镜像的服务。构建完 Docker镜像后,就可在当前宿主机上运行。但如果想要在其他机器上运行这个镜像,就需要手动复制。此时可借助 Docker Registry来避免镜像的手动复制。
一个 Docker Registry可包含多个 Docker仓库,每个仓库可包含多个镜像标签,每个标签对应一个 Docker镜像。这跟 Maven的仓库有点类似,如果把 Docker Registry比作 Maven仓库的话,那么 Docker仓库就可理解为某个jar包,而镜像标签则可理解为jar包的版本号
3. docker容器文件挂载与端口映射
每docker run一下就会启动右边这样的一个容器,我们启动的容器是一个完整的运行环境,怎么体现完整性呢?因为mysql是安装在linux里面的,所以这个容器就是一个完整的linux
即:每一个docker容器都是一个完整的运行环境,是一个完整的linux,
那mysql安装到了这个linux里面,那mysql默认就有了一个端口3306,但是这个端口相当于是在2009870e21c3这个容器内部用的端口,如果我们想要使用mysql,需要将3306映射到linux
所谓的挂载就是容器内部的mysql运行,只要给/var/log/mysql产生了日志,那么我们就可以在linux下创建的文件夹下看到这个日志,有点像电脑的快捷方式,即相当于把我们容器内部的mysql的/var/log/mysql这个文件夹快捷方式放在我们linux外部的/mydata/mysql/log这个位置
所以我们在上面挂载了三个文件夹,第一个是容器内部mysql日志挂载到linux虚拟机外面创建了快捷方式
第二个是容器内部mysql相关配置信息/etc/mysql挂载到外部/mydata/mysql/conf目录下,相当于我们以后如果想要改mysql的配置,就进linux里面,来到/mydata/mysql/conf目录下,找我们配置,改了以后容器内部的/etc/mysql对应的配置也就跟着改了
第三个是把容器内部mysql运行期间的一些数据/var/lib/mysql(如mysql数据库运行期间需要持久化保存的一些数据都挂载到外部/mydata/mysql/data)
二 下载安装
Docker 是一个开源的商业产品,有两个版本:社区版(Community Edition,缩写为 CE)和企业版(Enterprise Edition,缩写为 EE)。企业版包含了一些收费服务,个人开发者一般用不到。下面的介绍都针对社区版
-
Docker 要求 CentOS 系统的内核版本高于 3.10,通过
uname -r
命令查看你当前的内核版本 -
使用 root 权限登录 Centos。确保 yum 包更新到最新
yum -y update
-
卸载旧版本(如果安装过旧版本的话)
yum remove docker docker-common docker-selinux docker-engine
-
安装需要的软件包, yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的
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
-
查看所有仓库中所有docker版本,并选择特定版本安装
yum list docker-ce --showduplicates | sort -r
-
安装docker(由于repo中默认只开启stable仓库,故这里安装的是最新稳定版20.10.8:2021-08-03)
sudo yum install docker-ce-20.10.8-3.el7
-
启动并加入开机启动
systemctl start docker.service
启动docker
systemctl enable docker.service
设置docker开机自启动
systemctl restart docker.service
重启docker -
验证安装是否成功(有client和service两部分表示docker安装启动都成功了)
docker version
-
卸载docker
yum -y remove docker-engine
三 基本概念
包含三大概念:镜像(image),容器(container),仓库(repository)
镜像相当于应用的安装包,在Docker部署的任何应用都需要先构建成为镜像,仓库是存放镜像的场所(容器是Docker镜像的载体,每个应用都分别运行在Docker的每个容器中)
1. 镜像
获取镜像的两种方式
- 通过dockerfile自行构建
- 通过docker pull拉取已有仓库镜像(docker pull从远程仓库拉取镜像到本地)
寻找镜像
docker search mysql
可能报如下错误
Error response from daemon: Get https://index.docker.io/v1/search?q=mysql&n=25: dial tcp 34.193.164.221:443: i/o timeout
【解决方式1】:
使用阿里云镜像加速器地址,登录阿里云(https://cr.console.aliyun.com/#/accelerator)
cd /etc/docker
,查看有没有 daemon.json。这是docker默认的配置文件如果没有新建,如果有,则修改。
vim daemon.json
{
"registry-mirrors": ["https://上面获取到的地址.mirror.aliyuncs.com"]
}
保存退出
重启docker服务
【解决方式2】:
如果上述方式无法成功,采用
-
cat /etc/resolv.conf
查看本机dns地址 - 通过
dig @183.60.83.19 registry-1.docker.io
找到可用IP,其中@后面的是本机的dns地址 - 尝试修改/etc/hosts强制docker.io相关的域名解析到其它可用IP
52.55.198.220 registry-1.docker.io
以后再次尝试
备注:
下载镜像
使用命令docker pull命令即可从 Docker Registry上下载镜像,执行该命令后,Docker会从 Docker Hub中的 java仓库下载最新版本的java镜像。如果要下载指定版本则在java后面加冒号指定版本,例如:docker pull java:8
列举本地所有镜像
docker images
以上列表含义如下
- REPOSITORY:镜像所属仓库名称。
- TAG:镜像标签。默认是 latest,表示最新。
- IMAGE ID:镜像 ID,表示镜像唯一标识。
- CREATED:镜像创建时间。
- SIZE: 镜像大小。
删除镜像(rmi=remove image)
docker rmi -f 镜像名称/镜像ID
查看已下载的Docker镜像latest具体版本
docker image inspect nginx:latest|grep -i version
2. 容器
2.1 容器操作命令
- 新建并启动容器
使用以下docker run命令即可新建并启动一个容器,该命令是最常用的命令,它有很多选项,下面将列举一些常用的选项
-i:运行容器
-d:后台守护进程方式运行容器、
--name:给容器添加名称
-p:公开容器端口给当前宿主机(p是public)
-v:挂载目录
-p选项:公开容器端口给当前宿主机(p是public),指定端口映射,有以下四种格式-- ip:hostPort:containerPort
-- ip::containerPort
-- hostPort:containerPort
-- containerPort
--net选项:指定网络模式,该选项有以下可选参数:
--net=bridge:默认选项,表示连接到默认的网桥
--net=host:容器使用宿主机的网络
--net=container:NAME-or-ID:告诉 Docker让新建的容器使用已有容器的网络配置
--net=none:不配置该容器的网络,用户可自定义网络配置
如docker run -d -p 91:80 nginx
这样就能启动一个 Nginx容器。在本例中,为 docker run添加了两个参数,含义如下:
-d 后台运行
-p 宿主机端口:容器端口 // 开放容器端口到宿主机端口
我们启动了tomcat容器,但是无法直接通过宿主机ip + 容器启动的端口访问,因为容器的端口并未开放给我们的宿主机来访问,我们需要在创建容器的那一刻开放一个端口才能在外部去访问这个容器冒号左边是公开给外界访问的端口,右边是容器的端口。将容器本身的端口公开给外面进行访问,外面是用91访问的容器的80端口*
访问 http://Docker宿主机 IP:91/,将会看到nginx的主界面
- 列出容器
用 docker ps命令即可列出运行中的容器
如需列出所有容器(包括已停止的容器),可使用-a参数。该列表包含了7列,含义如下
CONTAINER_ID:表示容器 ID。
IMAGE:表示镜像名称。
COMMAND:表示启动容器时运行的命令
CREATED:表示容器的创建时间
STATUS:表示容器运行的状态。UP表示运行中, Exited表示已停止
PORTS:表示容器对外的端口号
NAMES:表示容器名称。该名称默认由 Docker自动生成,也可使用 docker run命令的--name选项自行指定 - 停止容器
使用 docker stop命令,即可停止容器docker stop d7988a207d2c
其中d7988a207d2c是容器 ID,当然也可使用 docker stop容器名称来停止指定容器 - 强制停止容器
可使用 docker kill命令发送 SIGKILL信号来强制停止容器docker kill d7988a207d2c
- 启动已停止的容器
使用docker run命令,即可新建并启动一个容器。对于已停止的容器,可使用 docker start命令来启动docker start d7988a207d2c
- 查看容器所有信息
docker inspect d7988a207d2c
- 查看容器日志
docker container logs d7988a207d2c
-- 只看最近2分钟的容器输出日志 -f 动态输出,类似于tail -f,还可以添加-t即参数来为每条日志添加时间戳docker container logs d7988a207d2c -f --since=2m
- 查看容器里的进程
docker top d7988a207d2c
- 进入容器
使用docker container exec命令用于进入一个正在运行的docker容器。如果docker run命令运行容器的时候,没有使用-it参数,就要用这个命令进入容器。一旦进入了容器,就可以在容器的 shell 执行命令了
docker container exec -it d7988a207d2c /bin/bash
- 删除容器(该命令只能删除已停止的容器,不能删除运行中的容器,需要先stop容器),加-f会发送signalkill信号给容器,终止运行中的应用
docker rm 容器id
-- 删除所有容器docker rm $(docker ps -a -q)
- 查看容器占用情况
docker stats
- 重命名容器名称
docker rename oldname newname
容器与宿主机之间的数据拷贝
Docker cp 命令 | 菜鸟教程 (runoob.com)
启动容器的两种方式
- 基于镜像新建一个容器并启动该容器
docker run
- 终止状态下的容器重新启动
docker start 容器id
docker run和docker start的区别
一个是新建并启动 一个是启动已有的,docker run相当于执行了两步操作:将镜像放入容器中(docker create),然后将容器启动,使之变成运行时容器(docker start),即
docker run = docker create + docker start
2.2 容器的前台运行和后台运行
docker 容器默认会把容器内部第一个进程,也就是pid=1的程序作为docker容器是否正在运行的依据,如果docker 容器pid挂了,那么docker容器便会直接退出,也就是说Docker容器中必须有一个前台进程,否则认为容器已经挂掉。
因此你要在容器里运行的程序以前台进程的形式运行,当然,如果你的容器需要同时启动多个进程,那么也只需要,或者说只能将其中一个挂起到前台即可。
前台运行(可以通过停止命令行中断)
第一步:找到需要运行的镜像的名称和tag
第二步:执行如下命令
docker run -i 镜像名称:标签(如果是最新版,可以不加标签)
后台运行
docker run -di 镜像名称:标签(如果是最新版,可以不加标签)
3. 镜像与容器区别
镜像是文件,容器是进程
容器基于镜像创建,即容器进程依赖于镜像中的文件(如运行所需可执行文件,依赖软件),如tomcat进程依赖于运行所需的配置文件等等
四 将服务运行在docker上
4.1. 使用Dockerfile构建Docker镜像
Dockerfile是一个文本文件,其中包含了若干条指令,指令描述了构建镜像的细节
Dockerfile就是我们用来构建Docker镜像的源码,当然这不是所谓的编程源码,而是一些命令的组合,只要理解它的逻辑和语法格式,就可以编写Dockerfile了。
简单点说,Dockerfile的作用:它可以让用户个性化定制Docker镜像。因为工作环境中的需求各式各样,网络上的镜像很难满足实际的需求。
先来编写一个最简单的Dockerfile,以前文下载的Nginx镜像为例,来编写一个Dockerfile修改该Nginx镜像的首页
- 新建文件夹/app,在app目录下新建一个名为Dockerfile的文件,在里面增加如下内容:
FROM nginx
RUN echo '<h1>hello,this is dockerfile test on nginx</h1>'> /usr/share/nginx/html/index.html
该Dockerfile非常简单,其中的 FORM、 RUN都是 Dockerfile的指令。 FROM指令用于指定基础镜像, RUN指令用于执行命令
- 在Dockerfile所在路径执行以下命令构建镜像:
docker build -t nginx:naughty-man ./
其中,-t指定镜像名字,命令最后的点(.)表示Dockerfile文件所在路径 - 执行以下命令,即可使用该镜像启动一个 Docker容器
docker run -d -p 92:80 nginx:naughty-man
- 访问 http://Docker宿主机IP:92/,可看到下图所示界面
Dockerfile常见命令
命令 | 作用 |
---|---|
FROM image_name:tag | 非常核心的基础镜像 |
MAINTAINER user_name | 声明镜像作者 |
ENV key value | 设置环境变量(可以写多条) |
RUN command | 编译镜像时运行的脚本(可以写多条) |
CMD | 设置容器的启动命令 |
ENTRYPOINT | 设置容器的入口程序 |
ADD <src> <dest> | 添加文件,从src目录复制文件到容器的dest,其中 src可以是 Dockerfile所在目录的相对路径,也可以是一个 URL,还可以是一个压缩包 |
COPY <src> <dest> | 拷贝文件,和ADD命令类似,但不支持URL和压缩包 |
WORKDIR path_dir | 设置工作目录 |
ARG | 设置编译镜像时加入的参数 |
VOLUMN | 设置容器的挂载卷 |
EXPOSE | 声明容器在运行时对外提供的服务端口 |
注意:RUN命令在 image 文件的构建阶段执行,执行结果都会打包进入 image 文件;CMD命令则是在容器启动后执行。另外,一个 Dockerfile 可以包含多个RUN命令,但是只能有一个CMD命令。
注意,指定了CMD命令以后,docker container run命令就不能附加命令了(比如前面的/bin/bash),否则它会覆盖CMD命令。
注意:
docker -v 和Dockerfile 中VOLUME 区别
Dockerfile 中的 VOLUME 与 docker -v 区别
4.2 镜像构建示意图
4.3 使用Dockerfile构建服务镜像
下面我们通过几个步骤将我们所写的springboot项目jar包制作成镜像
- 上传我们需要部署的应用程序jar包到linux的/app/server目录,在jar包所在目录创建名为Dockerfile的文件
- 在Dockerfile中添加以下内容
# 基于哪个镜像,为java程序,因此依赖的基础镜像是java
FROM java:8
# 将本地文件夹挂载到当前容器
VOLUME /tmp
# 文件的名字通过一个参数来传递,这里定义一个JAR_FILE的参数名,比如myTestServer.jar
ARG JAR_FILE
# 拷贝外面传进来的文件到镜像里面,然后命名为app.jar
ADD ${JAR_FILE} ./app.jar
# 声明需要暴露的端口
EXPOSE 8090
# 配置容器启动后执行的命令
ENTRYPOINT [“java”,"-jar","/app.jar"]
- 使用docker build命令构建镜像
docker build --build-arg JAR_FILE=myTestServer.jar -t mytestserver:0.01 ./
使用-t选项指定了镜像的标签,mytestserver为镜像名称,0.01为标签(镜像名称必须为小写英文),最后的./表示到当前目录去查找Dockerfile文件
流程为先去下载基础镜像,然后在向下制作镜像
- 查看镜像是否构建成功 docker images
- 启动镜像,加-d可在后台启动
docker run -p 9007:8090 mytestserver:0.01
- 访问http://Docker宿主机IP:9007/,可正常显示我们自己的服务首页
- 查看容器日志
docker logs -f 容器id
4.4 使用Dockerfile编译、生成镜像
上面构建镜像我们需要手动敲命令,很不方便,插件 dockerfile-maven-plugin 可以帮助我们自动读取项目下的Dockerfile文件构建Docker镜像
(1)在项目根目录下创建Dockerfile文件
(2)在pom文件中添加如下配置
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.3.6</version>
<configuration>
<repository>${project.artifactId}</repository>
<buildArgs>
# 获取到当前项目打包后最终的jar包名字
<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
(3)执行mvn clean package dockerfile:build,这样就能触发上面的插件执行来帮我们构建生成镜像
4.5 一些相关的命令
docker login
登录 Docker镜像仓库,默认是 Docker hub
网友评论