Docker
简介
Docker 是一个开源的容器化平台,它允许开发者打包应用及其所有依赖项到一个标准化的单元中,这个单元被称为容器。容器化是一种轻量级的、可移植的、自给自足的软件运行环境。
Docker 的核心概念
- 容器(Container):
一个轻量级的执行环境
,包含了运行某个应用所需的代码、运行时、系统工具、库和设置。容器在运行时与其他容器相互隔离,并且共享同一操作系统内核。 - 镜像(Image): 容器的蓝本,包含有
创建容器所需的全部内容
。当你启动一个容器
时,Docker会基于镜像
来创建它。 - 仓库(Registry): 是Docker存储镜像的地方。最流行的公共仓库是Docker Hub,它包含了大量的预先构建好的镜像,可以直接下载使用。
容器和镜像具体是做什么的、有什么联系,后面会说。
Docker 的作用
- 简化配置: 开发者可以通过Docker快速构建一个复杂的软件堆栈,并确保这个堆栈在不同环境下始终如一地运行。
- 代码流水线管理: Docker可以帮助开发者将代码自动化构建并测试,实现
持续集成和部署
。 - 应用隔离: Docker保证了应用与应用之间的隔离,提高了安全性。
- 透明度: Docker镜像包含代码、运行时、系统工具、系统库和设置,减少了“在我这里运行正常”的问题。
- 微服务架构: Docker非常适合微服务架构,因为它支持每个服务都可以独立容器化。
- 资源利用率和效率: 与虚拟机相比,容器需要更少的系统资源,因为它们共享主机的内核,而不是模拟整个操作系统。
Docker 与虚拟机的比较
Docker容器通常被看作是虚拟机(Virtual Machine, VM)的一个轻量级替代品。两者最大的区别在于:
- 虚拟机: 在硬件级别模拟出多个执行环境,每个环境都有完整的操作系统和虚拟硬件,消耗资源较多。
- 容器: 不需要完整的操作系统实例,它们更加轻量,启动更快,占用资源更少。
一、镜像和容器的概念
在 Docker 中,镜像和容器是两个核心概念,它们之间有着密切的关系。理解它们的关系有助于更好地使用 Docker。
镜像(Image)
- 定义:镜像是一个轻量级的、独立的、可执行的软件包,包含运行某个应用程序所需的代码、运行时、库、环境变量和配置文件。镜像是一个只读模板,用于创建 Docker 容器。
- 用途:镜像是容器的基础。你可以把镜像看作是容器的蓝图或快照,提供了创建容器的所有必要信息。
- 存储:镜像存储在 Docker 注册表中(如 Docker Hub),可以从这些注册表中下载并用于创建容器。
容器(Container)
- 定义:容器是镜像的运行实例。容器是独立的、可移植的,并且可以在任何支持 Docker 的地方运行。容器添加了额外的可写层和执行环境。
- 用途:容器用于运行应用程序,确保应用程序及其依赖项在各种环境中一致运行。每个容器都是从镜像创建的,并在其上增加了一层可写层。
- 生命周期:容器可以启动、停止、删除和重启。容器的状态可以是运行、停止或退出。
镜像和容器的关系
- 创建容器:
- 容器是从镜像创建的。使用
docker run
命令可以从指定镜像创建并启动一个新的容器。 - 示例:
docker run -it ubuntu bash
从ubuntu
镜像创建并启动一个新的容器,并在其中运行bash
。
- 容器是从镜像创建的。使用
- 只读和可写:
- 镜像是只读的。当容器从镜像创建时,会在镜像的基础上添加一个可写层,这样容器中的更改不会影响原始镜像。
- 容器运行时,可以对文件系统进行更改,这些更改只保存在容器的可写层中。
- 一致性:
- 由于镜像包含了应用程序运行所需的一切,所以容器可以在任何支持 Docker 的系统上运行,确保了环境的一致性。
- 镜像的构建和层:
- 镜像可以通过 Dockerfile 构建。Dockerfile 是一个包含构建镜像步骤的脚本文件。
- 每个构建步骤创建一层,所有这些层共同构成最终的镜像。镜像的层是共享的,可以复用,节省存储空间。
宿主机
- 定义:宿主机是运行容器的物理或虚拟机。宿主机提供了操作系统层面支持,使得容器能够运行。在大多数情况下,宿主机提供了Docker Engine或其他容器运行时环境,这些环境能够管理容器的生命周期。
- 类比:把宿主机比作餐厅厨房,厨师(Docker Engine或其他容器运行时)在这里准备食材(镜像),然后烹饪成菜肴(容器)供客人享用。
既然要创建镜像,那我们一定要知道什么是dockerfile
二、Dockerfile
2.1 什么是Dockerfile
Dockerfile
是一个文本文件,它包含了一系列的指令和参数,这些指令和参数
定义了如何从一个基础镜像构建出一个新的 Docker 镜像。
每个指令通常创建镜像的一个新层,并对镜像进行修改。最终,Dockerfile 描述了完整的步骤,以及如何配置和运行在容器中的应用程序。
编写 Dockerfile 的过程就是定义必要的环境、复制所需文件、安装依赖项、配置运行时等步骤,以确保容器化的应用程序能够正确运行的过程。
2.2 Dockerfile中的常见指令
FROM
:定义了使用哪个基础镜像开始构建过程。WORKDIR
:设置工作目录,即接下来的指令执行的位置。
- COPY
:复制文件或目录到容器内。ADD
:与 COPY 类似,但可以处理远程URL和自动解压缩。RUN
:执行命令并创建新的镜像层,用于安装软件包等。CMD
:提供容器启动时默认执行的命令。ENTRYPOINT
:配置一个容器启动时要运行的命令,允许将容器当作可执行程序。EXPOSE
:声明容器监听的端口。ENV
:设置环境变量。ARG
:定义构建时的变量。VOLUME
:定义匿名卷,可以在容器之间或容器和宿主机之间共享数据。USER
:设置运行容器时的用户名或UID。LABEL
:添加元数据到镜像,如作者、版本、描述等。ONBUILD
:当一个镜像被用作另一个 Dockerfile 的基础时执行的命令。HEALTHCHECK
:告诉 Docker 如何测试一个容器,以检查它是否仍在正常工作。
2.3Dockerfile实例
这个是自己某个diy项目中的Dockerfile:
# 这行指定了基础镜像 node 的版本为 21.6.2,
并且给这个构建阶段命名为 builder。这个基础镜像包括了Node.js运行环境及npm(Node包管理器)。
FROM node:21.6.2 as builder
# 将工作目录设置为容器内的 /app。后续的指令都会在这个目录下执行。
WORKDIR /app
# 这行将宿主机上的 package.json 和 package-lock.json 文件
# 复制到容器的当前工作目录下(/app)。这两个文件定义了项目依赖。
COPY package.json package-lock.json ./
# 安装项目依赖
RUN npm install
# 接着,复制当前目录下的所有内容到容器的工作目录。
# 由于之前已经添加了 package.json 和 package-lock.json,
# 这里通常会排除这两个文件和其他不需要的文件,比如通过 .dockerignore 文件。
COPY . .
# 构建应用程序
# 启动构建过程,并生成最终的静态文件。这些构建好的文件通常被放置在 dist 目录下。
RUN npm run build
# 使用官方的 Nginx 作为基础镜像
# 开始新的构建阶段,并使用 nginx 官方镜像作为基础。
# 这意味着前面的 builder 阶段完成后,这个新阶段开始时会从一个全新的Nginx镜像开始。
FROM nginx
# 从前一个阶段,也就是 builder 中复制 dist 目录下的所有内容到Nginx容器的 /var/www/html。
# 这是Nginx默认的文档根目录,存放静态文件供客户端访问。
COPY --from=builder /app/dist /var/www/html
# 将宿主机上的 nginx.conf 配置文件复制到容器的 /etc/nginx/conf.d/default.conf。
# 这会覆盖Nginx容器默认的配置文件。
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 声明容器在运行时会监听端口80。
# 虽然 EXPOSE 指令本身不会发布端口,但它作为镜像元数据存在,告诉使用该镜像的人应该发布哪个端口。
EXPOSE 80
# 启动 Nginx
# 设置容器启动时默认执行的命令,即启动Nginx服务。
# 这里 -g "daemon off;" 参数确保Nginx在前台运行,而不是作为守护进程。
CMD ["nginx", "-g", "daemon off;"]
2.4 详细扩展
(这一块时间原因,有空更新)
三、镜像
3.1 镜像的创建
在上述Dockerfile书写好以后,运行对应命令
docker build -t my-web-app .
其中 -t my-web-app 是你为镜像指定的名称。
如果运行顺利,咱们使用查看指令
docker image ls
3.2对于镜像的一些常用命令
对于构建命令,最后的点别忘了带上,仔细看。
下面myimage:latset是指镜像的命名:标签,不要直接复制哦,记得要替换成自己的使用
不带命名直接构建镜像
docker build .
使用 -t 选项来命名你的镜像
构建出的镜像命名为 myapp 且标签为 1.0。如果你不提供标签,则默认会给镜像打上 latest 标签。
docker build -t myapp:1.0 .
查看本地所有镜像
docker image ls
显示一个镜像变更的历史
docker history myimage:latest
显示一个或多个镜像的详细配置信息和层次结构。
docker inspect myimage:latest
删除镜像
docker rmi myimage:latest
如果你开始忘了给镜像命名,先ls查看他的image ID,再使用下述命令
image ID 命名:标签
docker tag 1e0626aac7f4 myapp:latest
还有很多命令,后续实践中使用到我会补充。
关于镜像标签,我在这稍微聊聊
3.3镜像标签的作用
在 Docker 中,虽然不同的标签可以引用同一个镜像,但通常我们会利用标签来区分不同版本
的镜像。这是通过构建带有指定标签的新镜像版本,并推送到仓库来实现的。每次应用更新或代码变更,你都会构建一个新的镜像,并给它一个新的版本号作为标签。
例如,你可能有一个应用的多个版本的镜像,如下所示:
docker build -t myapp:1.0.0 .
docker build -t myapp:1.0.1 .
docker build -t myapp:1.1.0 .
这里,1.0.0、1.0.1 和 1.1.0 是不同版本的标签,它们对应于不同版本的应用。每个标签都指向了在特定时间点构建的唯一镜像。
同时,为了方便用户始终能够拉取最新版本的镜像,还可以额外提供一个 latest 标签。在大多数情况下,latest 标签用于指向最新稳定版本的镜像。在发布新的稳定版本时,除了给该版本打上具体的版本号标签之外,还会更新 latest 标签以指向它:
docker build -t myapp:1.2.0 .
一个镜像可以有多个标签
docker tag myapp:1.2.0 myapp:latest
在这种情况下,即使 myapp:latest 和 myapp:1.2.0 标签指向同一个镜像,用户可以选择使用 latest 来始终保持使用最新版,或者使用具体的版本标签 1.2.0 来固定在特定版本。
总结一下,分版本涉及以下步骤:
- 构建不同版本:每次应用程序更新,你构建一个新的镜像版本。
- 使用标签区分:为每个镜像构建赋予一个独特的版本号标签。
- 可选地维护 latest 标签:让 latest 标签始终指向最新的稳定版本镜像。
通过这种方式,你能清晰地管理和分发不同版本的 Docker 镜像。
四、容器
4.1 创建一个容器
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
[OPTIONS]
是可选参数,例如 -d 用于后台运行,-p 用于端口映射,–name 来指定容器名称等。IMAGE
是你想要运行的镜像的名称。[COMMAND]
是启动后在容器内执行的命令。[ARG...]
是传递给命令的额外参数。
例子
假设你想要从 ubuntu 镜像创建一个容器,你可以执行以下命令:
docker run -it --name myubuntu ubuntu /bin/bash
这条命令会做以下几件事情:
- -it 保证你能够以交互模式连接到容器的终端。
- –name myubuntu 给你创建的容器指定了一个名字 “myubuntu”。
- ubuntu 指定了你将要使用的镜像名称。
- /bin/bash 是在容器内部运行的命令,这里让你进入了 bash shell。
如果你想要在后台运行一个容器,可以使用 -d(detached)选项:
docker run -d --name mynginx -p 80:80 nginx
在这个例子中:
- -d 指定容器在后台运行。
- –name mynginx 给容器指定了一个名字 “mynginx”。
- -p 80:80 表示将容器的 80 端口映射到宿主机的 80 端口上。
- nginx 是镜像名称,这个命令会启动一个 Nginx web 服务器。
要记住的是,在运行 docker run 命令时,如果本地没有指定的镜像,Docker 会去配置的镜像仓库下载它。一旦使用 docker run 创建了容器,并且容器停止后,你可以使用 docker start 命令再次启动它,而无需重新创建一个新的容器。
docker run --rm -it ubuntu /bin/bash
这条命令将创建并运行一个基于 ubuntu 镜像的容器,并提供一个交互式 bash shell。当你退出 bash(例如,通过键入 exit 命令或使用快捷键 Ctrl+D)时,容器将停止运行,且因为有 --rm 选项,它将立即被自动删除。
4.2 和容器相关的命令
查看所有活动中的容器
docker ps
查看所有容器,无论是否活动中
docker ps -a
启动容器
docker start <container_name_or_id>
例:docker start mycontainer
停止容器
docker stop 容器名/id
例:docker stop mycontainer
立马强制停止
由于 -t 0 的设置,Docker 不会等待任何宽限期,如果容器没有立即正常停止,
Docker 会立刻进行强制停止操作,可能会丢失数据
docker stop -t 0 my_temp_container
进入容器
以下是进入容器的一般命令,其中 -it 参数结合了两个选项:-i(或 --interactive)保持 STDIN 开放即使没有附加,-t(或 --tty)为该命令分配一个伪终端:
docker exec -it <container_name_or_id> /bin/bash
这里 <container_name_or_id> 是你想要进入的容器的名称或 ID,
而 /bin/bash 是在容器内部要运行的命令,
此例中是 Bash shell。如果容器内部没有安装 Bash,
你可能需要尝试使用 /bin/sh 或其他可用的 shell 程序。
如果成功,你会看到命令提示符变为容器内部的环境,例如:
root@a1b2c3d4e5f6:/#
可以输入 exit 来退出容器的 shell 环境。
4.3 容器端口或文件挂载宿主机
端口映射
端口映射允许从本地主机访问容器内部应用程序。你可以在 docker run 命令中使用 -p 或者 --publish 参数设置端口映射。
示例:端口映射
docker run -d \
--name webserver \
-p 8080:80 \
nginx:latest
这条命令会启动一个新的 Nginx 容器,并将容器内部监听的 TCP 端口 80 映射到宿主机的 TCP 端口 8080 上。这意味着你可以通过访问宿主机的 8080 端口来访问 Nginx 服务器。
挂载文件
在 Docker 中,有两种主要的方式来挂载文件和目录到容器中:–mount 和 -v(或 --volume)。
使用 --mount 标志
–mount 是 Docker 引入的较新的挂载选项,它具有更严格的规范格式。它通常被推荐用于新的部署和脚本,因为其语法更明确且更易阅读。
docker run -d \
--name devtest \
--mount type=bind,source="$(pwd)"/html,target=/usr/share/nginx/html \
nginx:latest
这里的参数:
- type=bind 表示这是一个绑定挂载。
- source=“$(pwd)”/html 指定了宿主机上要挂载的目录路径。
- target=/usr/share/nginx/html 指定了容器内的挂载点。
使用 -v 或 --volume 标志
-v 或 --volume 标志是 Docker 较早期的挂载选项,它允许简写形式和较灵活的路径表示方法。虽然它不像 --mount 那样规范,但仍然广泛用于很多 Docker 运行实例中。
docker run -d \
--name mynginx \
-v "$(pwd)"/html:/usr/share/nginx/html \
nginx:latest
在这个 -v 参数中:
- “$(pwd)”/html 是宿主机上的目录路径。
- /usr/share/nginx/html 是容器内的挂载点。
因此,为确保一致性以及避免混淆,你应当选择 --mount 或 -v 其中的一种,并且在部署过程中坚持使用同一种方式。如果你喜欢更明确且详述的风格,那么 --mount 可能是更好的选择;如果你偏好简短的命令,或者是需要维护旧的脚本,则可能会倾向于使用 -v。(我个人偏好-v)
(有空继续更新,docker的安装网上很多xdm自行去搜就好了)