当前位置: 首页 > news >正文

Docker详解

Docker是做什么的? 

Docker 可以帮助我们下载应用镜像,创建并运行镜像的容器,从而快速部署应用

什么是镜像?

将应用所需的函数库、依赖、配置等与应用一起打包得到的就是镜像 

什么是容器?

为每个镜像的应用进程创建的隔离运行环境就是容器 

什么是镜像仓库? 

存储和管理镜像的服务就是镜像仓库,
DockerHub 是目前最大的镜像仓库,其中包含各种常见的应用镜像

常见命令: 

  • docker run:创建并运行一个容器,-d是让容器在后台运行
  • --name mysql:给容器起一个名字
  • -p 3306:设置端口映射
  • -e KEY=VALUE:是设置环境变量
  • mysql:运行的镜像的名字

其中,比较常见的命令有:

命令

说明

文档地址

docker pull

拉取镜像

docker pull

docker push

推送镜像到DockerRegistry

docker push

docker images

查看本地镜像

docker images

docker rmi

删除本地镜像

docker rmi

docker run

创建并运行容器(不能重复创建)

docker run

docker stop

停止指定容器

docker stop

docker start

启动指定容器

docker start

docker restart

重新启动容器

docker restart

docker rm

删除指定容器

docs.docker.com

docker ps

查看容器

docker ps

docker logs

查看容器运行日志

docker logs

docker exec

进入容器

docker exec

docker save

保存镜像到本地压缩文件

docker save

docker load

加载本地压缩文件到镜像

docker load

docker inspect

查看容器详细信息

docker inspect

 2、数据卷

容器是隔离环境,容器内程序的文件、配置、运行时产生的容器都在容器内部,我们要读写容器内的文件非常不方便。大家思考几个问题:

  • 如果要升级MySQL版本,需要销毁旧容器,那么数据岂不是跟着被销毁了?

  • MySQL、Nginx容器运行后,如果我要修改其中的某些配置该怎么办?

  • 我想要让Nginx代理我的静态资源怎么办?

因此,容器提供程序的运行环境,但是程序运行产生的数据、程序运行依赖的配置都应该与容器解耦。 

2.1、什么是数据卷

数据卷(volume)是一个虚拟目录,是容器内目录宿主机目录之间映射的桥梁。

以Nginx为例,我们知道Nginx中有两个关键的目录:

  • html:放置一些静态资源

  • conf:放置配置文件

如果我们要让Nginx代理我们的静态资源,最好是放到html目录;如果我们要修改Nginx的配置,最好是找到conf下的nginx.conf文件。

但遗憾的是,容器运行的Nginx所有的文件都在容器内部。所以我们必须利用数据卷将两个目录与宿主机目录关联,方便我们操作。如图:

暂时无法在飞书文档外展示此内容

在上图中:

  • 我们创建了两个数据卷:confhtml

  • Nginx容器内部的conf目录和html目录分别与两个数据卷关联。

  • 而数据卷conf和html分别指向了宿主机的/var/lib/docker/volumes/conf/_data目录和/var/lib/docker/volumes/html/_data目录

这样以来,容器内的confhtml目录就 与宿主机的confhtml目录关联起来,我们称为挂载。此时,我们操作宿主机的/var/lib/docker/volumes/html/_data就是在操作容器内的/usr/share/nginx/html/_data目录。只要我们将静态资源放入宿主机对应目录,就可以被Nginx代理了。

/var/lib/docker/volumes这个目录就是默认的存放所有容器数据卷的目录,其下再根据数据卷名称创建新目录,格式为/数据卷名/_data

为什么不让容器目录直接指向宿主机目录呢

  • 因为直接指向宿主机目录就与宿主机强耦合了,如果切换了环境,宿主机目录就可能发生改变了。由于容器一旦创建,目录挂载就无法修改,这样容器就无法正常工作了。

  • 但是容器指向数据卷,一个逻辑名称,而数据卷再指向宿主机目录,就不存在强耦合。如果宿主机目录发生改变,只要改变数据卷与宿主机目录之间的映射关系即可。

数据卷的相关命令有:

命令

说明

文档地址

docker volume create

创建数据卷

docker volume create

docker volume ls

查看所有数据卷

docs.docker.com

docker volume rm

删除指定数据卷

docs.docker.com

docker volume inspect

查看某个数据卷的详情

docs.docker.com

docker volume prune

清除数据卷

docker volume prune

 注意:容器与数据卷的挂载要在创建容器时配置,对于创建好的容器,是不能设置数据卷的。而且创建容器的过程中,数据卷会自动创建

3.镜像

前面我们一直在使用别人准备好的镜像,那如果我要部署一个Java项目,把它打包为一个镜像该怎么做呢?

2.3.1.镜像结构

要想自己构建镜像,必须先了解镜像的结构。

之前我们说过,镜像之所以能让我们快速跨操作系统部署应用而忽略其运行环境、配置,就是因为镜像中包含了程序运行需要的系统函数库、环境、配置、依赖。

因此,自定义镜像本质就是依次准备好程序运行的基础环境、依赖、应用本身、运行配置等文件,并且打包而成。

举个例子,我们要从0部署一个Java应用,大概流程是这样:

  • 准备一个linux服务(CentOS或者Ubuntu均可)

  • 安装并配置JDK

  • 上传Jar包

  • 运行jar包

那因此,我们打包镜像也是分成这么几步:

  • 准备Linux运行环境(java项目并不需要完整的操作系统,仅仅是基础运行环境即可)

  • 安装并配置JDK

  • 拷贝jar包

  • 配置启动脚本

上述步骤中的每一次操作其实都是在生产一些文件(系统运行环境、函数库、配置最终都是磁盘文件),所以镜像就是一堆文件的集合

但需要注意的是,镜像文件不是随意堆放的,而是按照操作的步骤分层叠加而成,每一层形成的文件都会单独打包并标记一个唯一id,称为Layer)。这样,如果我们构建时用到的某些层其他人已经制作过,就可以直接拷贝使用这些层,而不用重复制作。

例如,第一步中需要的Linux运行环境,通用性就很强,所以Docker官方就制作了这样的只包含Linux运行环境的镜像。我们在制作java镜像时,就无需重复制作,直接使用Docker官方提供的CentOS或Ubuntu镜像作为基础镜像。然后再搭建其它层即可,这样逐层搭建,最终整个Java项目的镜像结构如图所示:

 

4.Dockerfile

由于制作镜像的过程中,需要逐层处理和打包,比较复杂,所以Docker就提供了自动打包镜像的功能。我们只需要将打包的过程,每一层要做的事情用固定的语法写下来,交给Docker去执行即可。

而这种记录镜像结构的文件就称为Dockerfile,其对应的语法可以参考官方文档:

https://docs.docker.com/engine/reference/builder/

其中的语法比较多,比较常用的有:

指令

说明

示例

FROM

指定基础镜像

FROM centos:6

ENV

设置环境变量,可在后面指令使用

ENV key value

COPY

拷贝本地文件到镜像的指定目录

COPY ./xx.jar /tmp/app.jar

RUN

执行Linux的shell命令,一般是安装过程的命令

RUN yum install gcc

EXPOSE

指定容器运行时监听的端口,是给镜像使用者看的

EXPOSE 8080

ENTRYPOINT

镜像中应用的启动命令,容器运行时调用

ENTRYPOINT java -jar xx.jar

例如,要基于Ubuntu镜像来构建一个Java应用,其Dockerfile内容如下:

# 指定基础镜像
FROM ubuntu:16.04
# 配置环境变量,JDK的安装目录、容器内时区
ENV JAVA_DIR=/usr/local
ENV TZ=Asia/Shanghai
# 拷贝jdk和java项目的包
COPY ./jdk8.tar.gz $JAVA_DIR/
COPY ./docker-demo.jar /tmp/app.jar
# 设定时区
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 安装JDK
RUN cd $JAVA_DIR \&& tar -xf ./jdk8.tar.gz \&& mv ./jdk1.8.0_144 ./java8
# 配置环境变量
ENV JAVA_HOME=$JAVA_DIR/java8
ENV PATH=$PATH:$JAVA_HOME/bin
# 指定项目监听的端口
EXPOSE 8080
# 入口,java项目的启动命令
ENTRYPOINT ["java", "-jar", "/app.jar"]

同学们思考一下:以后我们会有很多很多java项目需要打包为镜像,他们都需要Linux系统环境、JDK环境这两层,只有上面的3层不同(因为jar包不同)。如果每次制作java镜像都重复制作前两层镜像,是不是很麻烦。

所以,就有人提供了基础的系统加JDK环境,我们在此基础上制作java镜像,就可以省去JDK的配置了:

# 基础镜像
FROM openjdk:11.0-jre-buster
# 设定时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 拷贝jar包
COPY docker-demo.jar /app.jar
# 入口
ENTRYPOINT ["java", "-jar", "/app.jar"]

是不是简单多了

4.构建镜像

当Dockerfile文件写好以后,就可以利用命令来构建镜像了。

准备好了一个demo项目及对应的Dockerfile:

首先,我们将课前资料提供的docker-demo.jar包以及Dockerfile拷贝到虚拟机的/root/demo目录:

然后,执行命令,构建镜像:

# 进入镜像目录
cd /root/demo
# 开始构建
docker build -t docker-demo:1.0 .

命令说明:

  • docker build : 就是构建一个docker镜像

  • -t docker-demo:1.0-t参数是指定镜像的名称(repositorytag

  • . : 最后的点是指构建时Dockerfile所在路径,由于我们进入了demo目录,所以指定的是.代表当前目录,也可以直接指定Dockerfile目录:

# 直接指定Dockerfile目录
docker build -t docker-demo:1.0 /root/demo

结果:

查看镜像列表:

# 查看镜像列表:
docker images
# 结果
REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
docker-demo   1.0       d6ab0b9e64b9   27 minutes ago   327MB
nginx         latest    605c77e624dd   16 months ago    141MB
mysql         latest    3218b38490ce   17 months ago    516MB

然后尝试运行该镜像:

# 1.创建并运行容器
docker run -d --name dd -p 8080:8080 docker-demo:1.0
# 2.查看容器
dps
# 结果
CONTAINER ID   IMAGE             PORTS                                                  STATUS         NAMES
78a000447b49   docker-demo:1.0   0.0.0.0:8080->8080/tcp, :::8090->8090/tcp              Up 2 seconds   dd
f63cfead8502   mysql             0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp   Up 2 hours     mysql# 3.访问
curl localhost:8080/hello/count
# 结果:
<h5>欢迎访问商城, 这是您第1次访问<h5>

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • sh脚本发送邮件到多个收件人如何高效实现?
  • #Datawhale AI夏令营第4期#AIGC方向 文生图 Task2
  • 前端面试题整理-Javascript
  • 凤凰端子音频矩阵应用领域
  • 【问题解决】git status中文文件名乱码
  • #laravel部署安装报错loadFactoriesFrom是undefined method #
  • WordPress原创插件:Download-block-plugin下载按钮图标美化
  • 力扣面试经典算法150题:罗马数字转整数
  • 【JavaEE初阶】线程池
  • [LitCTF 2024]exx
  • 「MyBatis」实现留言板
  • LVS服务的搭建之NAT模式、DR模式的搭建实战
  • 情绪电商的数字化营销方法适用行业大揭秘
  • Linux的安装和使用
  • 使用RestHighLevelClient进行Elasticsearch Function Score查询
  • 9月CHINA-PUB-OPENDAY技术沙龙——IPHONE
  • 分享的文章《人生如棋》
  • .pyc 想到的一些问题
  • “寒冬”下的金三银四跳槽季来了,帮你客观分析一下局面
  • 【附node操作实例】redis简明入门系列—字符串类型
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • ES10 特性的完整指南
  • ES6 ...操作符
  • Javascript 原型链
  • Java教程_软件开发基础
  • Netty源码解析1-Buffer
  • NLPIR语义挖掘平台推动行业大数据应用服务
  • Octave 入门
  • python3 使用 asyncio 代替线程
  • Python十分钟制作属于你自己的个性logo
  • React Transition Group -- Transition 组件
  • React中的“虫洞”——Context
  • Yii源码解读-服务定位器(Service Locator)
  • 官方新出的 Kotlin 扩展库 KTX,到底帮你干了什么?
  • 解决jsp引用其他项目时出现的 cannot be resolved to a type错误
  • 两列自适应布局方案整理
  • 漫谈开发设计中的一些“原则”及“设计哲学”
  • 通过获取异步加载JS文件进度实现一个canvas环形loading图
  • 我与Jetbrains的这些年
  • (9)目标检测_SSD的原理
  • (pycharm)安装python库函数Matplotlib步骤
  • (solr系列:一)使用tomcat部署solr服务
  • (简单有案例)前端实现主题切换、动态换肤的两种简单方式
  • (数据结构)顺序表的定义
  • (推荐)叮当——中文语音对话机器人
  • .bat批处理(十一):替换字符串中包含百分号%的子串
  • .gitignore文件设置了忽略但不生效
  • .NET C# 使用 iText 生成PDF
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .net 调用海康SDK以及常见的坑解释
  • .NET 中什么样的类是可使用 await 异步等待的?
  • .net经典笔试题
  • .NET业务框架的构建
  • .NET与 java通用的3DES加密解密方法
  • ::before和::after 常见的用法