Skip to content

镜像

Docker 类似于 Maven,镜像可以理解成是 Maven 的依赖包,当需要使用某些镜像的时候如果本地没有,那么就会前往中央仓库下载,然后安装到本地,下次使用直接使用本地的镜像

拉取远程镜像命令(官方示例)

sh
# 拉取镜像
docker pull hello-world

# 运行
docker run hello-world

hello-world

一个镜像的名称是由两部分组成的,一个是repository,还有一个是tag,一般情况下约定repository就是镜像名称,tag作为版本,默认为latest,表示最新版本。所以指定版本运行的话使用下面命令,tag可以省略(默认最新版)

sh
docker pull 名称:版本

查看全部镜像

sh
docker images

删除镜像

sh
docker rmi 镜像名称

系统镜像

所谓的镜像其实就是一个封装的操作系统,这个系统中有很多依赖如:JDK、MYSQL、Nginx等等内容,没有封装过的基本的系统镜像被称为 Base 镜像,项目就是基于 Base 镜像进行打包的(也可以不要,如之前的 hello-world 就是基于当前的系统执行)

相较于正常的系统,这些镜像去掉了系统内核,使用的内核是宿主机的内核,也就是说,你当前的系统内核版本是多少,这些系统镜像的内核版本就是多少(可以使用 uname -r 查看内核版本)

这些 Base 镜像基本都是由 Linux 的发行版本进行封装,如:Ubuntu、CentOS、Kali等

拉取 Base 镜像

sh
docker pull ubuntu

启动镜像

Docker 会对没有操作的容器进行关闭,如果直接启动系统镜像会瞬间关闭(因为它没有事情做,开着也是浪费资源)对于这种情况可以加上 -it 属性

sh
docker run -it ubuntu

-i 表示在容器上打开一个标准的输入接口,-t 表示分配一个伪tty设备,可以支持终端登录,一般这两个是一起使用,否则base容器启动后就自动停止了,退出时输入 exit

当想重新启动的时候可以使用 start 进行重新启动,一定要加上 -i 否则无法进入镜像终端

sh
docker start -i [容器名称/容器ID]
软件结构

在 Base 镜像中安装的软件是分层的,Base 镜像为底安装的软件会一层一层的叠加上去,封顶为容器层。如果不同层中存在相同位置的文件,那么上层的会覆盖掉下层的文件

最终看到的是一个叠加之后的文件系统。当需要修改容器中的文件时,不会直接对镜像中的文件镜像进行修改,修改的是容器层,不会影响到下面的镜像

结构示例
容器层
......
软件二(MySql)
软件一(Nginx)
Base 地基

分层的好处:拿 Base 镜像举例,现在有两个镜像,底层的 Base 镜像是同一个,那么不采用分层结构的话这个 Base 镜像会被安装两遍造成无意义的资源浪费。但是采用分层的话 Base 镜像只需要安装一遍即可,这个 Base 镜像会被共享使用

既然是被共享使用,那这个镜像的文件就不能够被改变,否则就失去了通用性,想要进行改变而不失去通用性就需要使用封顶的容器层

可以使用 history 命令查看镜像层等

sh
docker history 镜像名称

构建镜像

首先拉取一下 Base 镜像

shell
docker pull ubuntu

commit方式(不推荐)

运行镜像

sh
docker run -it ubuntu

更新一下 apt

sh
apt update

安装一下JDK

sh
apt install openjdk-17-jdk

先退出 Base 系统镜像,然后使用 commit 构建

sh
docker commit [容器名称/容器ID] 新的镜像名称

image-20240525201044028

优点:自定义程度很高

缺点:构建效率太低,作为使用者来说,构建情况不透明有安全风险

dockerfile

跟 commit方式 不同的是这种构建方式是采用命令的形式进行构建,类似于 win 的批处理

先创建一个名为 Dockerfile 文件(名称不可随意更改)

sh
vim Dockerfile

输入格式:

dockerfile
FROM <基础镜像>
RUN <执行的命令>

# 案例
FROM ubuntu
RUN apt update
# 因为在构建过程中是无法干预的所以要加入-y 确认安装
RUN apt install -y openjdk-17-jdk

Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大

输入完命令之后,保存退出,然后输入以下命令构建

sh
docker build -t <镜像名> <构建文件的目>
参数说明示例
-t (--tag)指定镜像名称和标签docker build -t myapp:v1 .
--build-arg传递构建参数(需在 Dockerfile 中定义)docker build --build-arg VERSION=1.0 .
--no-cache禁用构建缓存docker build --no-cache .
--target多阶段构建时指定目标阶段docker build --target=prod .
-f (--file)指定 Dockerfile 路径docker build -f ./Dockerfile.prod .

image-20240525211205956

-t:设置镜像名称

不对其进行指定的话默认查找的是 Dockerfile 这个文件,可以使用 -f 或者 --file 参数来指定 Dockerfile 的路径和文件名,如:

sh
docker build -f mycustom-Dockerfile .

在这个命令中,mycustom-Dockerfile 是自定义的 Dockerfile 文件名,. 指示 Docker 在当前目录下寻找该文件

SpringBoot程序镜像

在项目根目录创建 Dockerfile 文件,并配置(IDEA)一下Docke,采用TCP套接字,然后在Docke服务器更改一下 service 文件

sh
vim /etc/systemd/system/multi-user.target.wants/docker.service

添加标红内容 -H tcp://0.0.0.0

image-20240527102647867

重启Docker服务,如果是云服务器,记得开启2375 TCP连接端口

sh
systemctl daemon-reload && systemctl restart docker.service

image-20240527103215911

对项目进行打包,然后编写 Dockerfile 文件

dockerfile
# Base 镜像
FROM ubuntu
# 作者
LABEL authors="曦暮流年"
# 安装JDK环境
RUN apt update && apt install -y openjdk-17-jdk
# 复制jar包
COPY target/weiliao-0.0.1.jar app.jar
# 启动命令,在容器启动的时候执行的命令
CMD java -jar app.jar

打包好的镜像会存放在服务器中,可以使用以下命令运行

sh
docker run -d -p 8080:8080 [镜像]

容器

通过 run 命令运行之后就会产生容器

sh
# 查看所有的容器
docker ps -a

# 查看运行中的容器
docker ps

如果是仅仅创建容器不进行启动的话,可以使用以下命令来进行创建容器

sh
docker create hello-world

一个镜像可以创建多个容器,每个容器都有一个随机的容器ID,后面是容器的创建时间以及当前的运行状态,最后一列是容器的名称,在创建容器时,名称如果没有指定会自动生成,可以在使用 run 命令时使用 --name 参数进行手动指定名称启动

sh
docker run --name=hello hello-world

开启/关闭容器

使用 docker startdocker stop 命令来开启和关闭容器

sh
# 开启容器
docker start [容器名称/容器ID]

# 关闭容器:等待善后工作完成再进行终止
docker stop [容器名\ID]
# 关闭容器:强制停止容器
docker kill [容器名称/容器ID]

# 重启容器
docker restart [容器名称/容器ID]

不可以直接使用镜像名称来进行开启或者关闭操作,需要使用容器名称或者容器ID

删除容器

不可使删除正在运行中的容器,需要先停止容器,然后再删除容器,如果希望在容器停止运行后自动删除可以使用以下命令

sh
# 删除容器
docker rm [容器名称/容器ID]

# 容器停止运行后自动删除
docker run --rm 镜像名称

如果没有挂在数据卷的话,那么所有的数据都是保存在容器中,所以删除容器的时候,容器中的数据也会被删除

暂停容器

容器暂时停止运行,但不是真的停止了运行。暂停运行后无法处理工作

sh
# 暂停运行
docker pause [容器名称/容器ID]
# 继续运行
docker unpause [容器名称/容器ID]