草庐IT

【云原生 | 05】Docker中容器的创建与启停

小鹏linux 2023-04-12 原文

🍁博主简介
        🏅云计算领域优质创作者
        🏅2022年CSDN新星计划python赛道第一名

        🏅2022年CSDN原力计划优质作者
        🏅阿里云ACE认证高级工程师
        🏅阿里云开发者社区专家博主

💊交流社区CSDN云计算交流社区欢迎您的加入!

目录

1. 镜像和容器

2. 新建并启动容器

3. 使用第一个容器

4. 容器命名

5.重启容器

6. 附着到容器上

 👑👑👑结束语👑👑👑


1. 镜像和容器

看待镜像和容器的一种方式是将它们类比成程序与进程。一个进程可以视为一个被执行的应用程序,同样,一个Docker容器可以视为一个运行中的Docker镜像。
标题Docker镜像与容器
如果大家熟悉面向对象原理,看待镜像和容器的另一种方法是将镜像看作类而将容器看作对象。对象是类的具体实例,同样,容器是镜像的实例。用户可以从单个镜像创建多个容器,就像对象一样,它们之间全都是相互隔离的。不论用户在对象内修改了什么,都不会影响类的定义——它们从根本上就是不同的东西。

2. 新建并启动容器

首先,我们会查看Docker是否能正常工作,然后学习基本的Docker的工作流:创建并管理容器。我们将浏览容器的典型生命周期:从创建、管理到停止,直到最终删除。
第一步,查看docker程序是否存在,功能是否正常:
[root@localhost ~]# sudo docker info
Containers: 1
Images: 8
Storage Driver: aufs
    Root Dir: /var/lib/docker/aufs
    Backing Filesystem: extfs
    Dirs: 10
Execution Driver: native-0.2
Kernel Version: 3.13.0-43-generic
Operating System: Ubuntu 14.04.2 LTS
CPUs: 1
Total Memory: 994 MiB
Name: riemanna
ID: DOIT:XN5S:WNYP:WP7Q:BEUP:EBBL:KGIX:GO3V:NDR7:YW6E:VFXT:FXHM WARNING: No swap limit support

在这里我们调用了docker可执行程序的info命令,该命令会返回所有容器和镜像(镜像即是Docker用来构建容器的“构建块”)的数量、Docker使用的执行驱动和存储驱动(execution and storage driver),以及Docker的基本配置。

Docker是基于客户端-服务器构架的。它有一个docker程序,既能作为客户端,也可以作为服务器端。作为客户端时,docker程序向Docker守护进程发送请求(如请求返回守护进程自身的信息),然后再对返回的请求结果进行处理。
现在,让我们尝试启动第一个Docker容器。我们可以使用docker run命令创建容器。
docker run命令提供了Docker容器的创建到启动的功能:
[root@localhost ~]# sudo docker run -i -t ubuntu /bin/bash
Unable to find image 'ubuntu' locally
ubuntu:latest: The image you are pulling has been verified 511136ea3c5a: Pull complete
d497ad3926c8: Pull complete
ccb62158e970: Pull complete
e791be0477f2: Pull complete
3680052c0f5c: Pull complete
22093c35d77b: Pull complete
5506de2b643b: Pull complete
Status: Downloaded newer image for ubuntu:latest
root@fcd78e1a3569:/#
官方文档列出了完整的Docker命令列表,也可以使用docker help获取这些命令。此外,还可以使用Docker的man页(即执行man docker-run)。
[root@localhost ~]# sudo docker run -i -t ubuntu /bin/bash

上述命令中:

        -t  选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上,
        -i  则让容器的标准输入保持打开。
利用docker run来创建并启动容器时,Docker在后台运行的标准操作包括:
        ·检查本地是否存在指定的镜像,不存在就从公有仓库下载;
        ·利用镜像创建一个容器,并启动该容器;
        ·分配一个文件系统给容器,并在只读的镜像层外面挂载一层可读写层;
        ·从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中;
        ·从网桥的地址池配置一个IP地址给容器;
        ·执行用户指定的应用程序;
        ·执行完毕后容器被自动终止。
官方文档上列出了docker run命令的所有标志,此外还可以用命令docker help run查看这些标志。或者,也可以用Docker的man页(也就是执行man docker-run命令)。
接下来,我们告诉Docker基于什么镜像来创建容器,示例中使用的是ubuntu镜像。ubuntu镜像是一个常备镜像,也可以称为“基础”(base)镜像,它由Docker公司提供,保存在Docker HubRegistry上。可以以ubuntu基础镜像(以及类似的fedora、debian、centos等镜像)为基础,在选择的操作系统上构建自己的镜像。到目前为止,我们基于此基础镜像启动了一个容器,并且没有对容器增加任何东西。
首先Docker会检查本地是否存在ubuntu镜像,如果本地还没有该镜像的话,那么Docker就会连接官方维护的Docker Hub Registry,查看Docker Hub中是否有该镜像。Docker一旦找到该镜像,就会下载该镜像并将其保存到本地宿主机中。
随后,Docker在文件系统内部用这个镜像创建了一个新容器。该容器拥有自己的网络、IP地址,以及一个用来和宿主机进行通信的桥接网络接口。最后,我们告诉Docker在新容器中要运行什么命令,在本例中我们在容器中运行/bin/bash命令启动了一个Bash shell。
当容器创建完毕之后,Docker就会执行容器中的/bin/bash命令,这时就可以看到容器内的shell了,如下:
root@f7cbdac22a02:/#

3. 使用第一个容器

现在,我们已经以root用户登录到了新容器中,容器的ID f7cbdac22a02,乍看起来有些令人迷惑的字符串`。这是一个完整的Ubuntu系统,可以用它来做任何事情。下面就来研究一下这个容器。首先,我们可以获取该容器的主机名,如下:
root@f7cbdac22a02:/# hostname 
f7cbdac22a02
可以看到,容器的主机名就是该容器的ID。再来看看/etc/hosts文件内容:
root@f7cbdac22a02:/# cat /etc/hosts
172.17.0.4 f7cbdac22a02
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
Docker已在hosts文件中为该容器的IP地址添加了一条主机配置项。
再来看看容器的网络配置情况,如下:
root@f7cbdac22a02:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 1500 qdisc noqueue state
    UNKNOWN group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
899: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast
    state UP group default qlen 1000
link/ether 16:50:3a:b6:f2:cc brd ff:ff:ff:ff:ff:ff
inet 172.17.0.4/16 scope global eth0
inet6 fe80::1450:3aff:feb6:f2cc/64 scope link valid_lft forever preferred_lft forever
可以看到,这里有lo的环回接口,还有IP为172.17.0.4的标准 eth0网络接口,和普通宿主机是完全一样的。我们还可以查看容器中运行的进程,如下:
root@f7cbdac22a02:/# ps -aux
USER PID %CPU %MEM    VSZ RSS TTY    STAT START TIME COMMAND
root    1 0.0 0.0    18156 1936 ?    Ss    May30 0:00 /bin/bash 
root    21 0.0 0.0   15568 1100 ?    R+    02:38 0:00 ps -aux
接下来尝试安装一个软件包:
root@f7cbdac22a02:/# apt-get update && apt-get install vim
通过上述命令,就在容器中安装了Vim编辑器软件。
用户可以继续在容器中做任何自己想做的事情。当所有工作都结束时,输入exit,就可以返回到Ubuntu宿主机的命令行提示符了。
但是,容器现在已经停止运行了!只有在指定的/bin/bash命令处于运行状态的时候,我们的容器也才会相应地处于运行状态。一旦退出容器,/bin/bash命令也就结束了,这时容器也随之停止了运行。
但容器仍然是存在的,可以用docker ps -a命令查看当前系统中容器的列表,如下:
CONTAINER ID IMAGE     COMMAND    CREATED  STATUS PORTS NAMES
1cd57c2cdf7f ubuntu:14.04 "/bin/bash" A minute Exited
    gray_cat
默认情况下,当执行docker ps命令时,只能看到正在运行的容器。如果指定-a标志的话,那么docker ps命令会列出所有容器,包括正在运行的和已经停止的。
注意:也可以为docker ps命令指定-l标志,列出最后一个运行的容器,无论其正在运行还是已经停止。也可以通过--format标志,进一步控制显示哪些信息,以及如何显示这些信息
从该命令的输出结果中我们可以看到关于这个容器的很多有用信息:ID、用于创建该容器的镜像、容器最后执行的命令、创建时间以及容器的退出状态(在上面的例子中,退出状态是0,因为容器是通过正常的exit命令退出的)。我们还可以看到,每个容器都有一个名称。
有3种方式可以唯一指代容器:短UUID(如f7cbdac22a02)、长UUID(如f7cbdac22a02e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778)或者名称(如gray_cat)。

4. 容器命名

Docker会为我们创建的每一个容器自动生成一个随机的名称。例如,上面我们刚刚创建的容器就被命名为gray_cat。如果想为容器指定一个名称,而不是使用自动生成的名称,则可以用--name标志来实现,如下:
[root@localhost ~]# sudo docker run --name bob_the_container -i -t ubuntu /bin/bash 
root@aa3f365f0f4e:/# exit
上述命令将会创建一个名为bob_the_container的容器。一个合法的容器名称只能包含以下字符:小写字母a~z、大写字母A~Z、数字 0~9、下划线、圆点、横线(如果用正则表达式来表示这些符号,就是[a-zA-Z0-9_.-])
在很多Docker命令中,都可以用容器的名称来替代容器ID,后面我们将会看到。容器名称有助于分辨容器,当构建容器和应用程序之间的逻辑连接时,容器的名称也有助于从逻辑上理解连接关系。具体的名称(如web、db)比容器ID和随机容器名好记多了。我推荐大家都使用容器名称,以更加方便地管理容器。
容器的命名必须是唯一的。如果试图创建两个名称相同的容器,则命令将会失败。如果要使用的容器名称已经存在,可以先用docker rm命令删除已有的同名容器后,再来创建新的容器。

5.重启容器

容器已经停止了,我们可以用下面的命令重新启动一个已经停止的容器,如下:
[root@localhost ~]# sudo docker start bob_the_container
除了容器名称,也可以用容器ID来指定容器,
[root@localhost ~]# sudo docker start aa3f365f0f4e
也可以使用docker restart命令来重新启动一个容器。
这时运行不带-a标志的docker ps命令,就应该看到我们的容器已经开始运行了。
类似地,Docker也提供了docker create命令来创建一个容器,但是并不运行它。这让我们可以在自己的容器工作流中对其进行精准化的控制。

6. 附着到容器上

Docker容器重新启动的时候,会沿用docker run命令时指定的参数来运行,因此我们的容器重新启动后会运行一个交互式会话shell。此外,也可以用docker attach命令,重新附着到该容器的会话上,如下:
[root@localhost ~]# sudo docker attach bob_the_container
也可以使用容器ID,重新附着到容器的会话上,如下:
[root@localhost ~]# sudo docker attach aa3f365f0f4e
现在,又重新回到了容器的Bash提示符,如下:
root@aa3f365f0f4e:/_#_
可能需要按下回车键才能进入该会话。
如果退出容器的shell,容器会再次停止运行。
容器是直接提供应用服务的组件,也是Docker实现快速启停和高效服务性能的基础。
在生产环境中,因为容器自身的轻量级特性,推荐大家使用容器时在一组容器前引入HA(High Availability,高可靠性)机制。例如使用HAProxy工具来代理容器访问,这样在容器出现故障时,可以快速切换到功能正常的容器。此外,建议通过指定合适的容器重启策略,来自动重启退出的容器。

 👑👑👑结束语👑👑👑

有关【云原生 | 05】Docker中容器的创建与启停的更多相关文章

  1. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  2. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  3. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  4. ruby-on-rails - 无法使用 Rails 3.2 创建插件? - 2

    我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby​​1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在

  5. ruby - 如何使用 RSpec::Core::RakeTask 创建 RSpec Rake 任务? - 2

    如何使用RSpec::Core::RakeTask初始化RSpecRake任务?require'rspec/core/rake_task'RSpec::Core::RakeTask.newdo|t|#whatdoIputinhere?endInitialize函数记录在http://rubydoc.info/github/rspec/rspec-core/RSpec/Core/RakeTask#initialize-instance_method没有很好的记录;它只是说:-(RakeTask)initialize(*args,&task_block)AnewinstanceofRake

  6. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

  7. ruby - 有人可以帮助解释类创建的 post_initialize 回调吗 (Sandi Metz) - 2

    我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法

  8. ruby - 使用多个数组创建计数 - 2

    我正在尝试按0-9和a-z的顺序创建数字和字母列表。我有一组值value_array=['0','1','2','3','4','5','6','7','8','9','a','b','光盘','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','','u','v','w','x','y','z']和一个组合列表的数组,按顺序,这些数字可以产生x个字符,比方说三个list_array=[]和一个当前字母和数字组合的数组(在将它插入列表数组之前我会把它变成一个字符串,]current_combo['0','0','0']

  9. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  10. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

随机推荐