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 容器数据:持久化
Docker 容器开发:虚拟化的更多相关文章
- 八种Docker容器开发模式解析
原文链接:http://www.csdn.net/article/2014-10-27/2822294 Docker优点已经说过很多次,这里不做详述,Docker现在越来越受到开发人员的青睐,而且利用 ...
- 快速理解Docker - 容器级虚拟化解决方案
是什么 简单的说Docker是一个构建在LXC之上的,基于进程容器(Processcontainer)的轻量级VM解决方案 拿现实世界中货物的运输作类比, 为了解决各种型号规格尺寸的货物在各种运输工具 ...
- [Docker] 容器开发环境最佳实践理论
保持 image 小 选择合适的 base image. 使用 multi-stage 构建. https://docs.docker.com/develop/develo ...
- 1.Docker容器学习之新生入门必备基础知识
0x00 Docker 快速入门 1.基础介绍 描述:Docker [ˈdɑ:kə(r)] 是一个基于Go语言开发实现的遵循Apache 2.0协议开源项目,目标是实现轻量级的操作系统虚拟化解决方案: ...
- docker容器的学习笔记
目录 Docker入门学习笔记(一) 1. 什么是Docker? 2. Docke的目标 3. Docker通常应用场景 4. Docker的基本组成 补:Docker容器相关技术简介 安装Docke ...
- 【linxu】部署docker容器虚拟化平台
实验所涉内容 Docker 概述 部署 docker 容器虚拟化平台 docker 平台基本使用方法 创建docker镜像和发布镜像方法 Container 容器端口映射 一 Docker 概述 Do ...
- Linux高级运维 第八章 部署docker容器虚拟化平台
8.1 Docker概述 实验环境: CENTOS7.4-63 64位 Dcoker概述 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到 ...
- URLOS开发基础教程——docker容器的使用方法
URLOS本是基于docker容器运行,在入门URLOS开发之前,我们首先需要掌握docker的相关基础知识,本篇就以docker容器的基本使用方法为例,快速的让大家对docker有一个全面的印象. ...
- 开发自己的 chart - 每天5分钟玩转 Docker 容器技术(167)
Kubernetes 给我们提供了大量官方 chart,不过要部署微服务应用,还是需要开发自己的 chart,下面就来实践这个主题. 创建 chart 执行 helm create mychart 的 ...
- spring boot本地开发与docker容器化部署的差异
spring boot本地开发与docker容器化部署的差异: 1. 文件路径及文件名区别大小写: 本地开发环境为windows操作系统,是忽略大小写的,但容器中区分大小写 2. docker中的容器 ...
随机推荐
- C#应用的用户配置窗体方案 - 开源研究系列文章
这次继续整理以前的代码.本着软件模块化的原理,这次笔者对软件中的用户配置窗体进行剥离出来,单独的放在一个Dll类库里进行操作,这样在其它应用程序里也能够快速的复用该类库,达到了快速开发软件的效果. 笔 ...
- JavaScript 中 toString 的奇妙使用
JavaScript 中的toString()方法,我们通常会一些其他类型的变量,转为字符串类型.但这里还有一些其他奇妙的用法. 不同的类型调用 toString() 会得到不同的结果.我们来一一分析 ...
- 开源Blazor UI组件库精选:让你的Blazor项目焕然一新!
今天给大家推荐一些开源.美观的Blazor UI组件库,这些优秀的开源框架和项目不仅能够帮助开发者们提高开发效率,还能够为他们的项目带来更加丰富的用户体验. 注:排名不分先后,都是十分优秀的开源框架和 ...
- kubernetes ingress部署
ingress概念 ingress与service,deployment同样都是k8s中的一种资源 ingress用于实现域名方式访问k8s内部应用 安装ingress 1. 安装helm: wget ...
- Java中类的构造 与 方法的重载
类的构造方法 定义:构造方法与类名相同,且没有返回值,且不需要void修饰 Car bmcar = new Car(); 特点:类中没有定义时,会默认有一个无参的构造方法,在无参的构造方法中为成员变量 ...
- 纯css+html+js模仿elementui组件
文件下载链接地址https://files.cnblogs.com/files/ht955/UIcomponents.zip?t=1717405975&download=true
- kettle从入门到精通 第五十一课 ETL之kettle Avro input
1.我们在学习nifi的过程中有接触到Avro schema,当时我在想kettle应该也支持Avro,果不其然kettle也是支持Avro文件的读和写的.今天我们一起来学习下kettle中如何使用A ...
- k8s配置文件管理
1.为什么要用configMap ConfigMap是一种用于存储应用所需配置信息的资源类型,用于保存配置数据的键值对,可以用来保存单个属性,也可以用来保存配置文件. 通过ConfigMap可以方便的 ...
- Mybatis中#{}和${}的区别:
简单来说 #{} 会在将参数加上引号,例如: SELECT * FROM user WHERE username=#{username} ; 带上参数后的SQL语句即: SELECT * ...
- 新手指引:前后端分离的springboot + mysql + vue实战案例
案例说明: 使用springboot + mysql + vue实现前后端分离的用户查询功能. 1.mysql:创建test数据库 -> 创建user数据表 -> 创建模拟数据: 2.sp ...