0x00 概述

容器是基于容器技术所建立和运行的轻量级应用运行环境,它是 Docker 封装和管理应用程序或微服务的“集装箱”。在 Docker 中,容器算是最核心的部分了,掌握容器的操作也是 Docker 中最基础的技能了。在这一节中,我们会深入了解容器,展示关于容器的操作。

0x01 容器的创建和启动

在了解容器的各项操作之前,我们再来回顾一下之前我们所提及的容器状态流转。

在这幅图中,我们可以看到,Docker 容器的生命周期里分为五种状态,其分别代表着:

在这幅图中,我们可以看到,Docker 容器的生命周期里分为五种状态,其分别代表着:

  • Created:容器已经被创建,容器所需的相关资源已经准备就绪,但容器中的程序还未处于运行状态。
  • Running:容器正在运行,也就是容器中的应用正在运行。
  • Paused:容器已暂停,表示容器中的所有程序都处于暂停 ( 不是停止 ) 状态。
  • Stopped:容器处于停止状态,占用的资源和沙盒环境都依然存在,只是容器中的应用程序均已停止。
  • Deleted:容器已删除,相关占用的资源及存储在 Docker 中的管理信息也都已释放和移除。

0x02 创建容器

当我们选择好镜像以后,就可以通过 docker create 这个命令来创建容器了。

$ sudo docker create nginx:1.12
34f277e22be252b51d204acbb32ce21181df86520de0c337a835de6932ca06c3

执行 docker create 后,Docker 会根据我们所给出的镜像创建容器,在控制台中会打印出 Docker 为容器所分配的容器 ID,此时容器是处于 Created 状态的。

之后我们对容器的操作可以通过这个容器 ID 或者它的缩略形式进行,但用容器 ID 操作容器就和用镜像 ID 操作镜像一样烦闷,所以我们更习惯于使用容器名来操作容器。

要使用容器名操作容器,就先得给容器命名,在创建容器时,我们可以通过 --name 这个选项来配置容器名。

sudo docker create --name nginx nginx:1.12

0x03 启动容器

通过 docker create 创建的容器,是处于 Created 状态的,其内部的应用程序还没有启动,所以我们需要通过 docker start 命令来启动它。

sudo docker start nginx

由于我们为容器指定了名称,这样的操作会更加自然,所以我们非常推荐为每个被创建的容器都进行命名。

当容器启动后,其中的应用就会运行起来,容器的几个生命周期也会绑定到了这个应用上,这个之前我们已经提及,这里就不在赘述。只要应用程序还在运行,那么容器的状态就会是 Running,除非进行一些修改容器的操作。

在 Docker 里,还允许我们通过 docker run 这个命令将 docker create 和 docker start 这两步操作合成为一步,进一步提高工作效率。

$ sudo docker run --name nginx -d nginx:1.12
89f2b769498a50f5c35a314ab82300ce9945cbb69da9cda4b022646125db8ca7

通过 docker run 创建的容器,在创建完成之后会直接启动起来,不需要我们再使用 docker start 去启动了。

这里需要注意的一点是,通常来说我们启动容器会期望它运行在“后台”,而 docker run 在启动容器时,会采用“前台”运行这种方式,这时候我们的控制台就会衔接到容器上,不能再进行其他操作了。我们可以通过 -d 或 --detach 这个选项告诉 Docker 在启动后将程序与控制台分离,使其进入“后台”运行。

0x04 管理容器

容器创建和启动后,除了关注应用程序是否功能正常外,我们也会关注容器的状态等内容。

通过 docker ps 这个命令,我们可以罗列出 Docker 中的容器。

$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
89f2b769498a nginx:1.12 "nginx -g 'daemon of…" About an hour ago Up About an hour /tcp nginx

默认情况下,docker ps 列出的容器是处于运行中的容器,如果要列出所有状态的容器,需要增加 -a或 --all 选项。

$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
425a0d3cd18b redis:3.2 "docker-entrypoint.s…" minutes ago Created redis
89f2b769498a nginx:1.12 "nginx -g 'daemon of…" About an hour ago Up About an hour /tcp nginx

在 docker ps 的结果中,我们可以看到几项关于容器的信息。其中 CONTAINER ID、IMAGE、CREATED、NAMES 大家都比较容易理解,分别表示容器 ID,容器所基于的镜像,容器的创建时间和容器的名称。

结果中的 COMMAND 表示的是容器中主程序 ( 也就是与容器生命周期所绑定进程所关联的程序 ) 的启动命令,这条命令是在镜像内定义的,而容器的启动其实质就是启动这条命令。关于 COMMAND 的更多知识,我们在之后的 Docker 镜像制作中会更详细的解读。

结果中的 STATUS 表示容器所处的状态,其值和我们之前所谈到的状态有所区别,主要是因为这里还记录了其他的一些信息。在这里,常见的状态表示有三种:

  • Created 此时容器已创建,但还没有被启动过。
  • Up [ Time ] 这时候容器处于正在运行状态,而这里的 Time 表示容器从开始运行到查看时的时间。
  • Exited ([ Code ]) [ Time ] 容器已经结束运行,这里的 Code 表示容器结束运行时,主程序返回的程序退出码,而 Time 则表示容器结束到查看时的时间。

有些读者有疑问,既然是列出容器,应该为命令取一些带有 ls 字眼的名字,为啥会用类似 Linux 中查看进程的 ps 呢?这其实有一部分历史原因,由于容器并非真的包裹住了进程,而只是隔离了进程,进程还是允许在宿主机操作系统之上的,所以列出镜像的过程到更新是查看正在运行的进程,故而有了这样的名字。

当然,在 Docker 逐渐成熟后,命令的命名也没有原来那么随意了,已经逐渐转换为使用大家广泛认可的形式。只是 docker ps 这条命令,还保留着复古的风格。

0x05 停止和删除容器

要将正在运行的容器停止,我们可以使用 docker stop 命令。

$ sudo docker stop nginx

容器停止后,其维持的文件系统沙盒环境还是存在的,内部被修改的内容也都会保留,我们可以通过 docker start 命令将这个容器再次启动。

当我们需要完全删除容器时,可以通过 docker rm 命令将容器进行删除。

$ sudo docker rm nginx

正在运行中的容器默认情况下是不能被删除的,我们可以通过增加 -f 或 --force 选项来让 docker rm 强制停止并删除容器,不过这种做法并不妥当。

0x06 随手删除容器

与其他虚拟机不同,Docker 的轻量级容器设计,讲究随用随开,随关随删。也就是说,当我们短时间内不需要使用容器时,最佳的做法是删除它而不是仅仅停止它。

有的读者会问,容器一旦删除,其内部的文件系统变动也就消失了,这样做岂不是非常麻烦。要解决这个疑惑,其根本是解决为什么我们会对容器中的文件系统做更改。我这里总结了两个对虚拟环境做更改的原因,以及在 Docker 中如何优雅的解决它们。

  • 在使用虚拟机或其他虚拟化所搭建的虚拟环境时,我们倾向于使用一个干净的系统镜像并搭建程序的运行环境,由于将这类虚拟环境制作成镜像的成本较高,耗时也非常久,所以我们对于一些细小的改动倾向于修改后保持虚拟环境不被清除即可。而在 Docker 中,打包镜像的成本是非常低的,其速度也快得惊人,所以如果我们要为程序准备一些环境或者配置,完全可以直接将它们打包至新的镜像中,下次直接使用这个新的镜像创建容器即可。

  • 容器中应用程序所产生的一些文件数据,是非常重要的,如果这些数据随着容器的删除而丢失,其损失是非常巨大的。对于这类由应用程序所产生的数据,并且需要保证它们不会随着容器的删除而消失的,我们可以使用 Docker 中的数据卷来单独存放。由于数据卷是独立于容器存在的,所以其能保证数据不会随着容器的删除而丢失。关于数据卷的具体使用,在之后的小节会专门讲解。

解决了这两个问题,大家心中的疑虑是不是就小了很多。而事实上,容器的随用随删既能保证在我们不需要它们的时候它们不会枉占很多资源,也保证了每次我们建立和启动容器时,它们都是“热乎”的崭新版本。大家都知道,系统卡就重装,而借助 Docker 秒级的容器启停特性,我们就是可以这么任性的“重装”。

0x07 进入容器

很多时间,我们需要的操作并不仅仅是按镜像所给出的命令启动容器而已,我们还会希望进一步了解容器或操作容器,这时候最佳的方式就是让我们进入到容器了。

我们知道,容器是一个隔离运行环境的东西,它里面除了镜像所规定的主进程外,其他的进程也是能够运行的,Docker 为我们提供了一个命令 docker exec 来让容器运行我们所给出的命令。

这里我们试试用容器中的 more 命令查看容器的主机名定义。

$ sudo docker exec nginx more /etc/hostname
::::::::::::::
/etc/hostname
::::::::::::::
83821ea220ed

docker exec 命令能帮助我们在正在运行的容器中运行指定命令,这对于服务控制,运维监控等有着不错的应用场景。但是在开发过程中,我们更常使用它来作为我们进入容器的桥梁。

熟悉 Linux 的朋友们知道,我们操作 Linux 这个过程,并不是 Linux 内部的某些机能,而是通过控制台软件来完成的。控制台软件分析我们的命令,将其转化为对 Linux 的系统调用,实现了我们对 Linux 的操作。若不是这样,生涩的系统调用方法对普通开发者来说简直就是黑洞一般的存在,更别提用它们控制系统了。

在 Linux 中,大家熟悉的控制台软件应该是 Shell 和 Bash 了,它们分别由 sh 和 bash 这两个程序启动。

说到这里,有读者一定想到了,既然有这两个控制台程序,我们只要在容器里执行它们,然后通过它们去控制容器内的环境,岂不就可以“自由的飞翔”了吗。没错,这里说的进入容器,就是通过 docker exec 命令来启动 sh 或 bash,并通过它们实现对容器内的虚拟环境的控制。

由于 bash 的功能要比 sh 丰富,所以在能够使用 bash 的容器里,我们优先选择它作为控制台程序。

$ sudo docker exec -it nginx bash
root@83821ea220ed:/#

在借助 docker exec 进入容器的时候,我们需要特别注意命令中的两个选项不可或缺,即 -i 和 -t( 它们俩可以利用简写机制合并成 -it )。

其中 -i ( --interactive ) 表示保持我们的输入流,只有使用它才能保证控制台程序能够正确识别我们的命令。而 -t ( --tty ) 表示启用一个伪终端,形成我们与 bash 的交互,如果没有它,我们无法看到 bash 内部的执行结果。

熟悉通过在容器中执行控制台程序进而进入容器这种方法,在开发过程中你能更轻松的观察容器中发生了什么,也更容易排查程序或者环境引起的问题。

0x08 衔接到容器

Docker 为我们提供了一个 docker attach 命令,用于将当前的输入输出流连接到指定的容器上。

$ sudo docker attach nginx

这个命令最直观的效果可以理解为我们将容器中的主程序转为了“前台”运行 ( 与 docker run 中的 -d 选项有相反的意思 )。

由于我们的输入输出流衔接到了容器的主程序上,我们的输入输出操作也就直接针对了这个程序,而我们发送的 Linux 信号也会转移到这个程序上。例如我们可以通过 Ctrl + C 来向程序发送停止信号,让程序停止 ( 从而容器也会随之停止 )。

在实际开发中,由于 docker attach 限制较多,功能也不够强大,所以并没有太多用武之地,这里我们就一笔带过,不做详细的解读了。

Docker学习笔记之运行和管理容器的更多相关文章

  1. Docker学习笔记 - 在运行中的容器内启动新进程

    docker psdoker top dc1 # 容器情况# 在运行中的容器内启动新进程docker exec [-d] [-i] [-t] 容器名 [command] [args]docker ex ...

  2. Docker学习笔记之--.Net Core应用容器通过网桥连接Redis容器(环境:centos7)

    上节演示通过应用容器连接sql server容器,连接:Docker学习笔记之--.Net Core项目容器连接mssql容器(环境:centos7) 本节演示安装 redis容器,通过网桥连接 先决 ...

  3. Docker学习笔记之--.Net Core项目容器连接mssql容器(环境:centos7)

    前一节演示在docker中安装mssql,地址:Docker学习笔记之--安装mssql(Sql Server)并使用Navicat连接测试(环境:centos7) 本节演示 .Net Core项目容 ...

  4. DOCKER 学习笔记5 Springboot+nginx+mysql 容器编排

    前言 在上节的内容中,我们已经通过一个简单的实例,将Docker-compose 进行了实际的应用.这一小节中.我们将通过学习和了解,着重认识容器的编排,上一节只算是一个小小的测试.在这一节中.我们将 ...

  5. DOCKER 学习笔记4 认识DockerCompose 多容器编排

    前言 通过上一节的学习,学会了如何在Linux 环境下搭建Docker并且部署Springboot 项目,并且成功的跑了起来,当然,在生产环境中,不只是需要一个后端的Web 项目,还需要比如 Ngin ...

  6. Docker学习笔记4: Docker-Compose—简化复杂容器应用的利器

    本文转载自http://www.tuicool.com/articles/AnIVJn. 因Python语言,个人也没学过,不是太熟悉,这篇文章的代码格式排版不准确爆了很多错,让我走了好多坑,不过还是 ...

  7. Docker学习笔记-简单运行.netcore

    前言: 环境:centos7.5 64 位 正文: 拉取 microsoft/dotnet, 安装完毕后执行 docker images 可以看到本地已经包含 microsoft/dotnet #包含 ...

  8. Docker学习笔记之一,搭建一个JAVA Tomcat运行环境

    Docker学习笔记之一,搭建一个JAVA Tomcat运行环境 前言 Docker旨在提供一种应用程序的自动化部署解决方案,在 Linux 系统上迅速创建一个容器(轻量级虚拟机)并部署和运行应用程序 ...

  9. Docker学习笔记 - Docker容器内部署redis

    Docker学习笔记(2-4)Docker应用实验-redist server 和client的安装使用 一.获取redis容器(含客户端和服务端) 二.创建服务端容器 1.在终端A中运行redis- ...

随机推荐

  1. vi相关

    vi有三种模式: 命令模式:键盘的任意输入都当成“编辑命令”: 输入模式:键盘的任意输入都当成文本内容: 末行模式:键盘的任意输入都当成“文本管理命令” 命令模式(刚打开)==>(i,a,o)输 ...

  2. Python 初始函数

    python之路——初识函数   阅读目录 为什么要用函数 函数的定义与调用 函数的返回值 函数的参数 本章小结 为什么要用函数 我们就想啊,要是我们能像使用len一样使用我们这一大段“计算长度”的代 ...

  3. sync修饰符的简易说明

    其实这个就说的很好了. sync会自动更新父组件的数据 原本valuechild 的值是222,父页面显示的222,把值传递给子组件 子组件也显示的222, 我点击子组件的按钮 把333传递给父组件, ...

  4. Apache服务安全加固

    一.账号设置 以专门的用户帐号和用户组运行 Apache 服务. 根据需要,为 Apache 服务创建用户及用户组.如果没有设置用户和组,则新建用户,并在 Apache 配置文件中进行指定. 创建 A ...

  5. SEO--简介

    SEO:搜索引擎优化 不需付费 SEM:搜索引擎营销 需要付费 IP:每个家庭每个公司应该是同个IP PV:网站刷新搜索总量 UV:独立用户访客

  6. vue中强制刷新的bug处理

    vue是单页面应用,跳转路由也是局部刷新,这里就拿后台管理系统而言,如果你的后台管理系统是左右布局,你不会遇到这样的问题,但是如果你的后台管理系统是上左右布局,你就会遇到这个问题,一级菜单在最上面,二 ...

  7. 只使用处理I/O的printDigit方法,编写一种方法一输出任意的double型量(可以是负的)

    /** * Question:只使用处理IO的printDigit函数,编写一个过程以输出任意double型量(可以为负) * @author wulei * 这道题我的理解是使用最基本的System ...

  8. python windows 安装jieba....

    用cmd进入到python安装路径,进入scripts文件夹,输出pip install jieba 安装完成提示

  9. jar包的读取

    昨天在做项目插件的时候,因为会用到jar包中的一个文件来初始化程序.并且以后还是会访问这个文件,所以就想到干脆吧文件拷贝到指定目录.在拷贝的时候也费了好一会时间,这里涉及到了jar文件的操作,在这里记 ...

  10. Spark_JGroupByKey

    package core.java; import java.util.Arrays; import java.util.List; import org.apache.spark.SparkConf ...