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

深入理解Docker,从入门到精通-Part1(基础使用)

一、Docker基本概念

Docker架构


基本组件的介绍

Docker Client 是用户界面,它支持用户与Docker Daemon之间通信
Docker Daemon Docker最核心的后台进程,运行于主机上,处理服务请求
Docker registry是中央registry,支持拥有公有与私有访问权限的Docker容器镜像的备份
Docker Containers负责应用程序的运行,包括操作系统、用户添加的文件以及元数据
Docker Images是一个只读模板,用来运行Docker容器
DockerFile是文件指令集,用来说明如何自动创建Docker镜像

三个基本概念

镜像

Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等),镜像不包含任何动态数据,其内容在构建之后也不会被改变。

简单理解,镜像就是一个文件,特殊之处在于能被Docker加载运行

但实际上并不是由单个文件组成那么简单,背后是一个文件系统,采用分层存储。

分层存储指的是镜像是由一组文件系统组成,或者说,由多层文件系统联合组成。

关键技术就是Union FS,联合文件系统是(Union FS)是linux的存储技术,也是Docker镜像的存储方式, 它是分层的文件系统,将不同目录拉到同一个虚拟目录下,下图展示了Docker用Union FS 搭建的分层镜像:(比如最下层是操作系统的引导,上一层是Linux操作系统,再上一层是Tomcat,jdk,再上一层是应用代码)

镜像构建时,会一层层构建,前一层是后一层的基础,每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。(比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除,在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像,因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉)

容器

镜像和容器的关系,就像是面向对象程序设计中的 类 和 实例 一样

镜像是静态的定义,容器是镜像运行时的实体,容器可以被创建、启动、停止、删除、暂停等。

        容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间,因此容器可以拥有自己的root文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。
        容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样,这种特性使得容器封装的应用比直接在宿主运行更加安全。
        前面讲过镜像使用的是分层存储,容器也是如此,每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为容器存储层。
        容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡,因此,任何保存于容器存储层的信息都会随容器删除而丢失。

仓库

镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜
像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。

一个 Docker Registry 中可以包含多个仓库( Repository );每个仓库可以包含多个标签
Tag );每个标签对应一个镜像。
通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本,我们
可以通过 < 仓库名>:<标签 > 的格式来指定具体是这个软件哪个版本的镜像,如果不给出标签,将以 latest 作为默认标签。
仓库名经常以 三段式路径 形式出现,比如 demo.com/nginx - proxy:tag ,前者往往意味着 Docker
Registry 多用户环境下的用户名,后者则往往是对应的软件名,但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务

二、Docker安装部署MySQL

1、下载镜像,这里以mysql5.7.41版本为例

docker pull mysql:5.7.41

2、 mysql配置

创建MySQL挂载目录,等会会解释什么是挂载路径

# 创建MySQL配置的文件夹
mkdir -p /tmp/etc/mysql
# 编辑my.cnf配置文件
vi /tmp/etc/mysql/my.cnf

配置MySQL忽略大小写,在我们创建的MySQL配置文件挂载点的目录的my.cnf文件加入如下内容

[mysqld]
lower_case_table_names=1

创建MySQL数据目录

因为默认MySQL启动后他的文件是在容器中的,如果我们删除容器,数据也将会消失,我们需要将数据挂载出来。

#创建mysql存储的目录
mkdir -p /tmp/data/mysql

启动MySQL

docker run -d -p 3306:3306 -v /tmp/etc/mysql:/etc/mysql/mysql.conf.d/ -v /tmp/data/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root --name mysql mysql:5.7.41

用docker ps查询,出现如下结果表明mysql启动成功

参数解释

  • -d:是指容器后台运行,如果不加-d,当用户断开客户端时容器会结束运行
  • -p:将容器的3306端口映射到主机的3306端口,用来暴漏端口的
  • -v:这个命令是用来挂载目录的,将本地目录挂载到容器中,这样容器操作的就是本地目录
  • -e:这个命令是配置环境参数的,这里MYSQL_ROOT_PASSWORD=root指的是用root用户运行mysql,可以登录Docker容器通过ENV命令查看
  • --name:这个命令是配置Mysql的容器名称的,如果不配置,默认是随机生成的名字

查看容器挂载的配置文件

可以通过docker exec -ti mysql /bin/bash命令登录容器,检查挂载的配置文件情况

我们可以看到我们修改的配置文件已经被挂载到了docker内部,这里面用到了exec命令,主要是在docker容器中运行命令

docker exec就是进入容器的命令,其中

-t 表示命令行交互模式      -i 表示展示容器输入信息STDIN

至此,MySQL安装部署成功

三、Docker安装部署Nacos

1、下载镜像,这里以nacos2.0.1版本为例

docker pull nacos/nacos-server:2.0.1

2、运行镜像

docker run -d -p 8848:8848 --name nacos --env MODE=standalone nacos/nacos-server:2.0.1

参数解释:

-d:后台进程运行

--name:容器名称

--env MODE=standlone:设置环境变量,这里表示单机模式启动

登录控制台,成功显示

至此,Nacos单机版安装部署成功

四、SpringBoot项目部署

将项目通过Maven进行打包,再去Target目录复制Jar包文件上传至服务器

 编写DockerFile文件

vi Dockerfile

具体内容如下:

FROM openjdk:8-jdk-alpine
VOLUME /tmp
ADD learn-docker-storage-1.0-SNAPSHOT.jar app.jar
EXPOSE 8003
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar"]

命令解释:

  • FORM:定制的镜像都是基于 FROM 的镜像,这里的 openjdk 就是定制需要的基础镜像,后续操作都是基于openjdk
  • VOLUME:挂载一个数据卷,这里因为没有名称,所以是一个默认的数据卷(后面详细解释)
  • ADD:添加一层镜像到当前镜像,这里就是添加SpringBootTest镜像到当前层,并改名app.jar
  • EXPOSE:暴漏端口,因为我们的自己的端口是8003,所以我们暴漏8003
  • ENTRYPOINT:设定容器启动时第一个运行的命令及其参数,这里就是容器以启动就执行 java -jar /app.jar

写好DockerFile后就需要用docker build命令来构建我们的镜像了,这样就可以将我们的SpringBoot项目打包成一个镜像了

构建一个镜像需要使用以下命令

docker bulid -t 仓库名/镜像名:tag .
  • -t  镜像的名字及标签,一般命名规则是 仓库名/镜像名:tag,

    • 仓库名:一般是私服或者dockerhub等地址,如果忽略默认就是dockerhub的地址docker.io.library/
    • 镜像名称:就是我们的自己的服务名称,可以随意命名
    • tag:就是我们的版本号
  • .  这个 . 表示当前目录,这实际上是在指定上下文的目录是当前目录,docker build 命令会将该目录下的内容打包交给 Docker 引擎以帮助构建镜像。

docker build -t learn-docker-storage:0.0.1 .

 

构建完成如果出现Successfully说明已经构建成功了

可以查看我们构建的镜像

启动镜像:

# 运行容器
docker run -d -p 8003:8003 learn-docker-storage:0.0.1

 查看启动日志

docker logs -f container_id

至此,我们的打包镜像部署服务就已经大功告成了

五、日志挂载优化

存储卷优化

什么是存储卷

“卷”是容器上的一个或多个“目录”,此类目录可绕过联合文件系统,与宿主机上的某个目录“绑定
(关联)”;

Docker 中,要想实现数据的持久化(所谓 Docker 的数据持久化即 数据不随着 Container 的结束
而结束 ),需要将数据从宿主机挂载到容器中。这些数据比如Mysql的数据、redis的数据、日志数据等等
Docker 管理宿主机文件系统的一部分,默认位于 /var/lib/docker/volumes 目录中;( 最常用的方

存储卷的使用

 查看存储卷

docker volume ls

 

我们发现都是匿名的存储卷,如何来确定都是那个呢,可以通过 docker inspect 容器 ID 来查看
存储信息
docker inspect 2041965c3e87|grep Mounts -A20

# 进入文件挂载目录 
cd /var/lib/docker/volumes/d35de1b7e4631908b05635db4c1f114ab3aafbdf25a9843c068696e6 6a779c75/_data 
# 输出日志 
tail -f learn-docker-storage.log

 当删除了容器,发现存储卷所挂载的目录数据依然还存在

bind挂载共享存储

什么是bind

Bind mounts模式和Volumes非常相似,不同点在于Bind mounts模式是将宿主机上的任意文件或文件夹挂载到容器,而Volumes本质上是将Docker服务管理的一块区域(默认是/var/lib/docker/volumes下的文件夹)挂载到容器。

共享存储

经过上面的测试,我们发现每一个容器都是单独用一个存储卷,用于临时文件没有问题的,但是如果要让容器都用同一个存储路径怎么办呢,这个时候就用到了 bind挂载了,可以使用-v进行挂载挂载刚才的存储卷。

# 级联创建文件夹
mkdir -p /tmp/data/logs
# 运行容器,指定挂载路径 
docker run -d -v /tmp/data/logs:/logs \
-p 8003:8003 --name learn-docker-storage \
learn-docker-storage:0.0.2

 用-v来指定需要挂载的目录,这也是我们用的最多的一种方式

使用docker inspect命令来检查容器详情

docker inspect learn-docker-storage|grep Mounts -A20

volume和bind的区别

对于多个容器需要共享访问同一数据目录,或者需要持久化容器内数据(如数据库)时,我们都是采用挂载目录形式(bind mounts),将宿主机的某一目录挂载到容器内的指定目录,这种方式能解决问题,但这种方式也一直有一些缺点

  • 容器在不同的服务器部署需要根据实际磁盘挂载目录修改路径
  • 不同操作系统的文件和目录权限会搞得你昏头转向,火冒三丈 ?

 bind mount和volume其实都是利用宿主机的文件系统,不同之处在于volume是docker自身管理的目录中的子目录,所以不存在权限引发的挂载的问题,并且目录路径是docker自身管理的,所以也不需要在不同的服务器上指定不同的路径,你不需要关心路径。

六、网络优化

我们先用一张图来说明为什么要进行网络优化

所以Docker的容器是否可以直接通过Docker的网卡进行直接通信呢?

答案是当然可以,这就叫做网络优化。

Docker网络原理

        Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关,因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。

       Docker网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法通过直接Container-IP访问到容器,如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主主机(端口映射),即docker run创建容器时候通过 -p 或 -P 参数来启用,访问容器的时候就通过[宿主机IP]:[容器端口]访问容器。

Docker网络模式

Docker网络模式配置说明
host模式–net=host容器和宿主机共享Network namespace。
container模式–net=container:NAME_or_ID容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace。
none模式–net=none容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair 和网桥连接,配置IP等。
overlay模式-- driver overlayDocker跨主机通信模式,使用分布式计算机架构后需要使用overlay网络模式
bridge模式–net=bridge(默认为该模式)

 Docker 的 bridge 模式是 Docker 容器网络的默认模式,它提供了一种简单而强大的方式来为容器分配独立的 IP 地址,并使它们能够在同一主机上相互通信。下面是对 bridge 模式的简要介绍:

桥接网络模式实战

查看网络列表

可以通过docker network ls命令查看网络列表

# 查看网络列表
docker network ls

创建一个桥接网络

默认容器启动会自动默认接入bridge的桥接网络,为了区分我们的服务也防止各种网络问题,我们创建一个专用网络,可以通过docker network create 网络名称来创建一个默认的桥接网络

# 创建一个桥接网络
docker network create learn-docker-network
# 查看网络列表
docker network ls

停止并删除原有容器

停止和删除我们的微服务以及mysql服务

# 删除当前运行中的容器
docker rm -f learn-docker-storage nacos mysql

创建MySQL

因为我们的微服务依赖MySQL先启动MySQL并接入网络,因为MySQL不需要通过宿主机访问,所有也不需要映射端口了,--network 是配置接入哪一个网络

docker run -d \
-v /tmp/etc/mysql:/etc/mysql/mysql.conf.d/ \
-v /tmp/data/mysql:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=root \
--name mysql --network=learn-docker-network \
mysql:5.7.38

这里需要注意:为什么重新建了个新的MySQL容器,能拿到以前的数据?因为我们做了存储卷映射,所以数据可以持久化

创建Nacos

我们的nacos是需要暴露端口的,因为我们需要外部能够看到nacos页面,但是我们也需要我们的nacos连接到当前网络

docker run -d  \
--network=learn-docker-network \
-p 8848:8848 \
--name nacos --env MODE=standalone \
nacos/nacos-server

查看网络详情

可以通过docker network inspect 网络名称可以查看当前的网络的详细信息

docker network inspect learn-docker-network

修改微服务配置

因为需要使用自定义网络访问mysql容器以及nacos容器,需要修改微服务数据库连接地址,

docker 网络访问 可以通过IP或者通过服务名称都是可以的,这里我们通过服务名称访问,因为我们使用了maven打包的方式,我们只需要将pom文件修改就可以

<properties>
    <mysql.addr>mysql:3306</mysql.addr>
    <nacos.addr>nacos:8848</nacos.addr>
</properties>

重新打包服务

将打包的文件上传服务器后按照上面步骤同上面打包,打包版本为 0.0.3

docker build -t learn-docker-storage:0.0.3 .

创建微服务

下面就按部就班的创建微服务就可以,只是注意需要加入网络,这里这个端口需要映射外网访问

docker run -d \
-v /tmp/data/logs:/logs \
-p 8003:8003 \
--name learn-docker-storage \
--network=learn-docker-network \
learn-docker-storage:0.0.3

测试微服务

到现在微服务已经启动,我们尝试访问以下

 curl http://192.168.64.153:8003/storage/employe/findByID/10001 | python -m json.tool

访问测试数据没有问题,到现在我们服务已经搭建完成,并且使用网络进行了优化


http://www.kler.cn/a/372105.html

相关文章:

  • 【CSS3】css开篇基础(6)
  • Linux线程安全(二)条件变量实现线程同步
  • 理解typeScript中的泛型,并在vue3项目中使用
  • Unity3D 逻辑服的ECS框架设计具体实现详解
  • Java 锁机制
  • 虚拟机桥接模式连不上,无法进行SSH等远程操作
  • 如何SSH到Openshift Node上设置相关网口的静态IP
  • LeetCode16:最接近的三数之和
  • 【网页布局技术】项目五 使用CSS设置导航栏
  • HarmonyOS 设备管理
  • 深入浅出梯度下降算法(学习笔记)
  • xlnt加载excel报错:‘localSheetId‘ expected
  • springboot日志配置
  • 力扣算法笔记——生成随机数组
  • 从单体架构到云原生架构演化图示
  • M1 Pro MacBook Pro 上的奇遇:Rust 构建失败,SIGKILL 惊魂记
  • 「C/C++」C++17 之 std::variant 安全的联合体(变体)
  • 【FinalShell问题】FinalShell连接虚拟机超时问题
  • Javaweb项目发布到阿里云服务器
  • MongoDB 部署指南:从 Linux 到 Docker 的全面讲解
  • AUTOSAT-PDUR模块
  • 【Linux】 su 和 sudo 的区别剖析
  • B计划在哪里?下一个10年我在哪里?
  • 基于uniapp微信小程序的餐厅预约点餐系统
  • NORDIC NPM1300是一款高度集成的电源管理集成电路
  • 封闭空间防碰撞无人机技术详解