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 标签记录
  • 使用推送,语法 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

/// 这便是一个简单的 Docker 容器开发流程:

拉取镜像 --> 创建容器 --> 开发容器 --> 生成镜像 --> tag 标签 --> 推送镜像
^ |
|------------- 继续开发 --------------|

补充说明:删除容器和镜像

  • 删除容器,需要先停止容器,然后使用 docker rm <container-id>
  • 清理掉所有处于终止状态的容器的快捷方式 docker container prune
  • 删除镜像使用 docker rmi <image-id>,记忆上镜像的删除无非是多个 i 表示 image

后续内容:Docker 容器数据:持久化




Docker 容器开发:虚拟化的更多相关文章

  1. 八种Docker容器开发模式解析

    原文链接:http://www.csdn.net/article/2014-10-27/2822294 Docker优点已经说过很多次,这里不做详述,Docker现在越来越受到开发人员的青睐,而且利用 ...

  2. 快速理解Docker - 容器级虚拟化解决方案

    是什么 简单的说Docker是一个构建在LXC之上的,基于进程容器(Processcontainer)的轻量级VM解决方案 拿现实世界中货物的运输作类比, 为了解决各种型号规格尺寸的货物在各种运输工具 ...

  3. [Docker] 容器开发环境最佳实践理论

      保持 image 小       选择合适的 base image.       使用 multi-stage 构建. https://docs.docker.com/develop/develo ...

  4. 1.Docker容器学习之新生入门必备基础知识

    0x00 Docker 快速入门 1.基础介绍 描述:Docker [ˈdɑ:kə(r)] 是一个基于Go语言开发实现的遵循Apache 2.0协议开源项目,目标是实现轻量级的操作系统虚拟化解决方案: ...

  5. docker容器的学习笔记

    目录 Docker入门学习笔记(一) 1. 什么是Docker? 2. Docke的目标 3. Docker通常应用场景 4. Docker的基本组成 补:Docker容器相关技术简介 安装Docke ...

  6. 【linxu】部署docker容器虚拟化平台

    实验所涉内容 Docker 概述 部署 docker 容器虚拟化平台 docker 平台基本使用方法 创建docker镜像和发布镜像方法 Container 容器端口映射 一 Docker 概述 Do ...

  7. Linux高级运维 第八章 部署docker容器虚拟化平台

    8.1  Docker概述 实验环境: CENTOS7.4-63 64位 Dcoker概述 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到 ...

  8. URLOS开发基础教程——docker容器的使用方法

    URLOS本是基于docker容器运行,在入门URLOS开发之前,我们首先需要掌握docker的相关基础知识,本篇就以docker容器的基本使用方法为例,快速的让大家对docker有一个全面的印象. ...

  9. 开发自己的 chart - 每天5分钟玩转 Docker 容器技术(167)

    Kubernetes 给我们提供了大量官方 chart,不过要部署微服务应用,还是需要开发自己的 chart,下面就来实践这个主题. 创建 chart 执行 helm create mychart 的 ...

  10. spring boot本地开发与docker容器化部署的差异

    spring boot本地开发与docker容器化部署的差异: 1. 文件路径及文件名区别大小写: 本地开发环境为windows操作系统,是忽略大小写的,但容器中区分大小写 2. docker中的容器 ...

随机推荐

  1. Android 13 - Media框架(6)- NuPlayer

    关注公众号免费阅读全文,进入音视频开发技术分享群! 上一节我们通过 NuPlayerDriver 了解了 NuPlayer 的使用方式,这一节我们一起来学习 NuPlayer 的部分实现细节. ps: ...

  2. kubernetes: pod升级与回滚扩容与缩容暂停恢复

    运行一个容器: apiVersion: apps/v1 kind: Deployment metadata: annotations: deployment.kubernetes.io/revisio ...

  3. 基于docker一键化部署LNMP环境

    cd / && wget https://files.cnblogs.com/files/superlinux/install_lnmp.sh && bash inst ...

  4. C++笔记(13)数组的引用和引用的数组

    数组的引用 数组有二个特性,影响作用在数组上的函数:一是不能复制数组,二是使用数组名时, 数组名会自动指向其第一个元素的指针. 因为不能复制,所以无法编写使用数组类型的形参,数组会自动转化为指针.比如 ...

  5. vue3+vant 引入Dialog Toast都会失败报错not defined

    今天在封装vant组件的时候,刚好要用到toast提示信息的组件,索性就按照官网提供的引入方法进行正常的引入,嘿,好家伙,一顿操作下来后发现竟然报Toast未定义,这就纳闷了,明明步骤都是对的啊,所以 ...

  6. [SWPUCTF 2021 新生赛]easy_sql

    这道题呢就是很简单的sql注入,我们直接用sqlmap来跑. 首先我们打开页面可以看见提示,参数为wllm **然后我们启动虚拟机,输入sqlmap的命令:sqlmap -u "url地址/ ...

  7. C#.NET与JAVA互通之AES加密解密V2024

    C#.NET与JAVA互通之AES加密解密V2024 视频: 注意点: 1. KEY 和 IV 从字符串转byte数组时,双方要约定好编码,一般是UTF8. 2.明文从字符串转byte数组时,双方要约 ...

  8. npm ERR! code EPERM npm ERR! syscall open npm ERR! path C:\Program Files\nodejs\node_cache\_cacache\

    报错信息 让人摸不着头脑的报错 解决方式 简单粗暴 直接删文件 方法1:需要删除npmrc文件. 强调:不是nodejs安装目录npm模块下的那个npmrc文件 而是在C:\Users{账户}\下的. ...

  9. nordic——long range测试

    简介:本案例测试了long range,注意nrf52系列芯片中,部分硬件是不支持CADE的,也就是不支持long range,如nrf52832就不支持long range.同时协议栈也是部分支持, ...

  10. 又跳槽!3年Java经验收割成都大厂的面试心得(干货满满&文末有福利)

    中厂->阿里->字节,成都->杭州->成都 系列文章目录和关于我 0.前言 笔者在不足两年经验的时候从成都一家金融科技中厂跳槽到杭州阿里淘天集团,又于今年5月份从杭州淘天跳槽到 ...