Docker 容器开发:虚拟化
Docker 容器开发:虚拟化
Docker 的核心价值在于虚拟化或者说环境隔离【通过虚拟化技术实现虚拟环境】,解决环境配置和部署的依赖问题实现解耦
我对虚拟化的理解源自《Operating Systems: Three Easy Pieces》,推荐阅读
容器技术相关历史推荐知乎上的这篇文章:容器技术的历史
Docker 基本概念
Docker 提供了在称为容器的松散隔离环境中打包和运行应用程序的能力
- 镜像(Image):镜像是一个只读的模板,用于创建 Docker 容器
- 容器(Container):容器是一个可运行的实例,是镜像的运行时实例
两者的关系类似于面向对象编程中的类和对象
Docker 生态系统
- Docker 注册表(Docker Registry):Docker 注册表是一个存储和分发 Docker 镜像的场所
- Docker 客户端(Docker Client):用于与 Docker 服务器交互的 CLI 工具
- Docker 服务器(Docker Server):Docker 服务器是一个守护进程,用于管理 Docker 对象,如镜像、容器、网络和卷
- Docker Hub:这是所有自定义镜像的存储库,类似于 GitHub
一种技术的发展离不开生态系统的支持,Docker 的生态系统也是 Docker 成功的重要原因之一,像 Git 与 GitHub、Node.js 与 npm、Python 与 PyPI 等技术都有类似的生态系统
关于 Docker 安装,这里不再赘述,可以参考官方文档:Get Docker
不过我比较好奇的是 Docker 是基于 Linux 的 Kernal 实现的,那么在 Windows 和 Mac 上如何运行呢?反正因为这个在 Windows 和 Mac 安装会相对麻烦一点。我只是练习使用是在虚拟机中使用 Debian 安装的
只不过需要说明一下,一般在安装 Docker 后,关于 Docker 相关内容需要使用 sudo 进行提权,如果想方便使用应该将你想使用的用户添加到 docker 组中,命令:
sudo usermod -aG docker $USER
Docker 使用容器
通过镜像创建容器
一般在创建容器的过程:
- Docker 守护进程首先尝试在本地仓库查找 Image
- 如果本地没有对应 Image 会继续远程拉取
- 在 Docker 守护进程成功获取 Image,后会通过 Image 创建 Container
示例:
# hello-world 镜像是用于测试的,通过下面命令可以创建对应容器并运行此容器 docker run hello-world #### 下面是会显示的内容 ##### # 这是本地没有 hello-world 镜像 Unable to find image 'hello-world:latest' locally # 下面是真的进行远程拉取,并创建容器 latest: Pulling from library/hello-world 2db29710123e: Pull complete Digest: sha256:ffb13da98453e0f04d33a6eee5bb8e46ee50d08ebe17735fc0779d0349e889e9 Status: Downloaded newer image for hello-world:latest # 下面是容器运行的内容,除了首行外我使用 ... 做了省略 😁 Hello from Docker! ...
-
其中的拉取操作可以单独进行,使用
docker pull <images-name>[:<version>]
-
其中
run
的语法大致是docker run <images-name>[:<version>]
-
使用
docker ps
可以查看所有 正在运行的容器,通过添加-a
选项可以查看所有可用dd简单说明,列表头的含义
- CONTAINER ID:显示每个容器的唯一 ID
- IMAGE:创建容器的图像
- COMMAND:启动时在容器中执行的命令
- CREATED:容器被创建的时间
- STATUS:容器的当前状态
- PORTS:如果任何容器端口映射情况
- NAMES:这是容器的名称,如果没有设置会随机生成一个并且是唯一的
说明一下
<>
表示里面的内容是变换的[]
表示里面的内容是可选的
接下来,需要简单说明一下镜像中的层,就是 hello-world 中 2db29710123e: Pull complete
做一下解释:
- 由于每个镜像都构建在 Linux 内核之上,因此它具有一些可以被其他镜像重用的共同依赖项
- Docker 将这些依赖项捆绑在一个堆栈中,这些堆栈称为层
- 只有指令 RUN、COPY、ADD 创建层,其他指令创建临时中间图像并且不会增加构建的大小
# 测试拉取 Nginx 这种相对 hello-world 大的镜像 docker pull nginx #### 结果 #### Using default tag: latest latest: Pulling from library/nginx # 被分五层 f1f26f570256: Pull complete 7f7f30930c6b: Pull complete 2836b727df80: Pull complete e1eeb0f1c06b: Pull complete 86b2457cc2b0: Pull complete 9862f2ee2e8c: Pull complete Digest: sha256:2ab30d6ac53580a6db8b657abf0f68d75360ff5cc1670a85acb5bd85ba1b19c0 Status: Downloaded newer image for nginx:latest docker.io/library/nginx:latest
- 分层不取决于镜像大小,它的决定性因素是设计者,在于共同依赖项的设计上,有时一个小镜像也会有大量分层
交互模式的容器,我们以 python:3.6
为例,先创建对应容器 docker run python:3.6
-
在使用
ps
查看时会发现没有容器,那是因为容器并没有运行,所以需要使用-a
选项CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8cc71dccbb99 python:3.6 "python3" 10 minutes ago Exited (0) 10 minutes ago cool_mendel fba35ad4d200 hello-world "/hello" About an hour ago Exited (0) About an hour ago elastic_wing -
们就一直在说 Docker 使用 Linux 内核作为容器,我们创建使用 bash 交互模式的容器
在运行容器时,使用
-it
选项【实际是两个选项联用】,语法是:docker run -it <image-name> bash
-t
完整选项是--tty
:作用是分配一个伪 tty-i
完整选项是--interactive
:作用是保持STDIN打开【即使未连接】,其实从 interactive 的中文意思就可以理解
# 创建使用 bash 交互式 tty 的 python:3.6 容器 docker run -it python:3.6 bash #### 结果:目前处于虚拟 Linux 操作系统中 #### root@84779de65a0b:/# #### 交互操作过程 #### # 使用 id 确认自己权限身份 root@84779de65a0b:/# id uid=0(root) gid=0(root) groups=0(root) # 退出 exit,提示如果退出容器它将停止,想要验证使用 docker ps 看有没有容器运行 root@84779de65a0b:/# exit exit learn@debian10:~$
- 现在我们能够创建可以访问 bash 的容器
如何再次使用停止的 Docker 容器
通过 docker ps -a
我们已经有三个容器,现在学习如何让停止的容器运行
docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 84779de65a0b python:3.6 "bash" 8 minutes ago Exited (0) 3 minutes ago romantic_meninsky 8cc71dccbb99 python:3.6 "python3" 37 minutes ago Exited (0) 37 minutes ago cool_mendel fba35ad4d200 hello-world "/hello" 2 hours ago Exited (0) 11 minutes ago elastic_wing
-
-
语法是
docker start <container-id>
,我们选择 romantic_meninsky【之前通过docker run -it python:3.6 bash
创建的容器】,类比推理如果要停止运行容器docker stop <container-id>
,重启使用docker restart <container-id>
learn@debian10:~$ docker start 84779de65a0b 84779de65a0b learn@debian10:~$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 84779de65a0b python:3.6 "bash" 16 minutes ago Up 6 seconds romantic_meninsky
-
-
romantic_meninsky 容器再次运行了,通过
docker exec -it <container-id|container-name> bash
可以重新登录容器的 bash,解释说明|
是或的意思在其中表示使用容器 ID 或容器名称,比如:docker exec -it 84779de65a0b bash
等价docker exec -it romantic_meninsky bash
docker exec -it 84779de65a0b bash #### 结果:再次进入容器 romantic_meninsky ### root@84779de65a0b:/# #### 容器内操作 #### # 我们将在容器中安装一些东西,以便我们可以在其中编写一些 python 脚本 # 修改 apt 源【国内镜像快一点】,命令 sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list root@84779de65a0b:/# sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list # 更新 apt 缓存,命令 apt update root@84779de65a0b:/# apt update # 安装一个编辑器,随意 vim, nano, ... 选你熟悉的 root@84779de65a0b:/# apt install vim # 编辑器创建 hello-world.py root@84779de65a0b:/# vim hello-world.py #### vim 编辑器内容,进入编辑器按 i 键会进入编辑器模式 #### print("Hello World") #### vim End,按 Esc 键切换模式,再按 : 键输入 wq 即可保存退出 #### # 运行 hello-world.py,当然这只是测试用,也可以写其他 Python 程序并运行 root@84779de65a0b:/# python hello-world.py Hello World # 退出 root@84779de65a0b:/# exit exit
- 我们可以通过这样的方法对容器进行开发
- 在实际开发环境中还会与一些编辑器进行联合使用,比如 Visual Studio Code
通过容器创建镜像
在经过这些操作后,容器内部已经发生变动,现在我们将这个容器打包为镜像,语法 docker commit -m "<commit-message>" <container-id|name> <new-image-name>:<version>
,这个有点像 Git 的提交操作,其中 -m
是添加注释信息的
docker commit -m "python36 Hello World Test" 84779de65a0b my-python36-hello-world:1.0 #### 结果:会输出一段 SHA256 作为生成镜像的哈希校验 #### sha256:2f12c4d8f189633c4b0b58e6496f429f125a125cdd47e016991af721569a763e # 通过 docker images 可以查看本地镜像仓库 docker images REPOSITORY TAG IMAGE ID CREATED SIZE my-python36-hello-world 1.0 2f12c4d8f189 2 minutes ago 958MB nginx latest 080ed0ed8312 7 days ago 142MB python 3.6 54260638d07c 15 months ago 902MB hello-world latest feb5d9fea6a5 18 months ago 13.3kB
通过下面操作可以将本地镜像推送到远程仓库 Docker Hub 中
- 你需要一个自己的 Docker Hub 帐户,并进行登录
docker login -u <username>
,建议登录时使用 Access Tokens 方式进行【在 https://hub.docker.com/ 上设置】,登出docker logout
-
- 设置 tag 标签,语法
docker tag <image-name>:<version> <username>/<image>:<version>
对于 tag 标签作用有点类似虚拟机拍摄快照,相当于镜像的快照,实际应该以版本为单位使用 tag 标签记录
- 设置 tag 标签,语法
- 使用推送,语法
docker push <username>/<image>:<version>
# 设置 tag 标签 docker tag my-python36-hello-world:1.0 shadow7749/my-python36-hello-world:1.0 learn@debian10:~$ docker tag my-python36-hello-world:1.0 shadow7749/my-python36-hello-world:1.0 # 查看本地镜像仓库变化 learn@debian10:~$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE my-python36-hello-world 1.0 2f12c4d8f189 29 minutes ago 958MB shadow7749/my-python36-hello-world 1.0 2f12c4d8f189 29 minutes ago 958MB nginx latest 080ed0ed8312 7 days ago 142MB python 3.6 54260638d07c 15 months ago 902MB hello-world latest feb5d9fea6a5 18 months ago 13.3kB # 推送,此操作必须确认你已经登录 learn@debian10:~$ docker push shadow7749/my-python36-hello-world:1.0 The push refers to repository [docker.io/shadow7749/my-python36-hello-world] ff540de539ad: Pushed aa4c808c19f6: Mounted from library/python 8ba9f690e8ba: Mounted from library/python 3e607d59ef9f: Mounted from library/python 1e18e7e1fcc2: Mounted from library/python c3a0d593ed24: Mounted from library/python 26a504e63be4: Mounted from library/python 8bf42db0de72: Mounted from library/python 31892cc314cb: Mounted from library/python 11936051f93b: Mounted from library/python 1.0: digest: sha256:790bdc67737ed40e747fa9f1b7fb2831ac09031811036d2c9bda3a4b4eb56b94 size: 2430
- 完成后,你可以登录 https://hub.docker.com/ 确认是否推送到远程仓库中
/// 这便是一个简单的 Docker 容器开发流程:
拉取镜像 --> 创建容器 --> 开发容器 --> 生成镜像 --> tag 标签 --> 推送镜像 ^ | |------------- 继续开发 --------------|
补充说明:删除容器和镜像
- 删除容器,需要先停止容器,然后使用
docker rm <container-id>
- 清理掉所有处于终止状态的容器的快捷方式
docker container prune
- 删除镜像使用
docker rmi <image-id>
,记忆上镜像的删除无非是多个i
表示 image
后续内容:Docker 容器数据:持久化
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了