mirror of
https://github.com/zhwei820/learn.lianglianglee.com.git
synced 2025-09-17 08:46:40 +08:00
967 lines
26 KiB
HTML
967 lines
26 KiB
HTML
<!DOCTYPE html>
|
||
|
||
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
|
||
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
|
||
<head>
|
||
|
||
<head>
|
||
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
|
||
|
||
<link rel="icon" href="/static/favicon.png">
|
||
|
||
<title>04 容器操作:得心应手掌握 Docker 容器基本操作.md.html</title>
|
||
|
||
<!-- Spectre.css framework -->
|
||
|
||
<link rel="stylesheet" href="/static/index.css">
|
||
|
||
<!-- theme css & js -->
|
||
|
||
<meta name="generator" content="Hexo 4.2.0">
|
||
|
||
</head>
|
||
|
||
|
||
|
||
<body>
|
||
|
||
|
||
|
||
<div class="book-container">
|
||
|
||
<div class="book-sidebar">
|
||
|
||
<div class="book-brand">
|
||
|
||
<a href="/">
|
||
|
||
<img src="/static/favicon.png">
|
||
|
||
<span>技术文章摘抄</span>
|
||
|
||
</a>
|
||
|
||
</div>
|
||
|
||
<div class="book-menu uncollapsible">
|
||
|
||
<ul class="uncollapsible">
|
||
|
||
<li><a href="/" class="current-tab">首页</a></li>
|
||
|
||
</ul>
|
||
|
||
|
||
|
||
<ul class="uncollapsible">
|
||
|
||
<li><a href="../">上一级</a></li>
|
||
|
||
</ul>
|
||
|
||
|
||
|
||
<ul class="uncollapsible">
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/00 溯本求源,吃透 Docker!.md.html">00 溯本求源,吃透 Docker!.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/01 Docker 安装:入门案例带你了解容器技术原理.md.html">01 Docker 安装:入门案例带你了解容器技术原理.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/02 核心概念:镜像、容器、仓库,彻底掌握 Docker 架构核心设计理念.md.html">02 核心概念:镜像、容器、仓库,彻底掌握 Docker 架构核心设计理念.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/03 镜像使用:Docker 环境下如何配置你的镜像?.md.html">03 镜像使用:Docker 环境下如何配置你的镜像?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
<a class="current-tab" href="/专栏/由浅入深吃透 Docker-完/04 容器操作:得心应手掌握 Docker 容器基本操作.md.html">04 容器操作:得心应手掌握 Docker 容器基本操作.md.html</a>
|
||
|
||
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/05 仓库访问:怎样搭建属于你的私有仓库?.md.html">05 仓库访问:怎样搭建属于你的私有仓库?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/06 最佳实践:如何在生产中编写最优 Dockerfile?.md.html">06 最佳实践:如何在生产中编写最优 Dockerfile?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/07 Docker 安全:基于内核的弱隔离系统如何保障安全性?.md.html">07 Docker 安全:基于内核的弱隔离系统如何保障安全性?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/08 容器监控:容器监控原理及 cAdvisor 的安装与使用.md.html">08 容器监控:容器监控原理及 cAdvisor 的安装与使用.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/09 资源隔离:为什么构建容器需要 Namespace ?.md.html">09 资源隔离:为什么构建容器需要 Namespace ?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/10 资源限制:如何通过 Cgroups 机制实现资源限制?.md.html">10 资源限制:如何通过 Cgroups 机制实现资源限制?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/11 组件组成:剖析 Docker 组件作用及其底层工作原理.md.html">11 组件组成:剖析 Docker 组件作用及其底层工作原理.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/12 网络模型:剖析 Docker 网络实现及 Libnetwork 底层原理.md.html">12 网络模型:剖析 Docker 网络实现及 Libnetwork 底层原理.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/13 数据存储:剖析 Docker 卷与持久化数据存储的底层原理.md.html">13 数据存储:剖析 Docker 卷与持久化数据存储的底层原理.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/14 文件存储驱动:AUFS 文件系统原理及生产环境的最佳配置.md.html">14 文件存储驱动:AUFS 文件系统原理及生产环境的最佳配置.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/15 文件存储驱动:Devicemapper 文件系统原理及生产环境的最佳配置.md.html">15 文件存储驱动:Devicemapper 文件系统原理及生产环境的最佳配置.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/16 文件存储驱动:OverlayFS 文件系统原理及生产环境的最佳配置.md.html">16 文件存储驱动:OverlayFS 文件系统原理及生产环境的最佳配置.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/17 原理实践:自己动手使用 Golang 开发 Docker(上).md.html">17 原理实践:自己动手使用 Golang 开发 Docker(上).md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/18 原理实践:自己动手使用 Golang 开发 Docker(下).md.html">18 原理实践:自己动手使用 Golang 开发 Docker(下).md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/19 如何使用 Docker Compose 解决开发环境的依赖?.md.html">19 如何使用 Docker Compose 解决开发环境的依赖?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/20 如何在生产环境中使用 Docker Swarm 调度容器?.md.html">20 如何在生产环境中使用 Docker Swarm 调度容器?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/21 如何使 Docker 和 Kubernetes 结合发挥容器的最大价值?.md.html">21 如何使 Docker 和 Kubernetes 结合发挥容器的最大价值?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/22 多阶级构建:Docker 下如何实现镜像多阶级构建?.md.html">22 多阶级构建:Docker 下如何实现镜像多阶级构建?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/23 DevOps:容器化后如何通过 DevOps 提高协作效能?.md.html">23 DevOps:容器化后如何通过 DevOps 提高协作效能?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/24 CICD:容器化后如何实现持续集成与交付?(上).md.html">24 CICD:容器化后如何实现持续集成与交付?(上).md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/25 CICD:容器化后如何实现持续集成与交付?(下).md.html">25 CICD:容器化后如何实现持续集成与交付?(下).md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/26 结束语 展望未来:Docker 的称霸之路.md.html">26 结束语 展望未来:Docker 的称霸之路.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
|
||
|
||
<div class="sidebar-toggle-inner"></div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<script>
|
||
|
||
function add_inner() {
|
||
|
||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||
|
||
inner.classList.add('show')
|
||
|
||
}
|
||
|
||
|
||
|
||
function remove_inner() {
|
||
|
||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||
|
||
inner.classList.remove('show')
|
||
|
||
}
|
||
|
||
|
||
|
||
function sidebar_toggle() {
|
||
|
||
let sidebar_toggle = document.querySelector('.sidebar-toggle')
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let content = document.querySelector('.off-canvas-content')
|
||
|
||
if (sidebar_toggle.classList.contains('extend')) { // show
|
||
|
||
sidebar_toggle.classList.remove('extend')
|
||
|
||
sidebar.classList.remove('hide')
|
||
|
||
content.classList.remove('extend')
|
||
|
||
} else { // hide
|
||
|
||
sidebar_toggle.classList.add('extend')
|
||
|
||
sidebar.classList.add('hide')
|
||
|
||
content.classList.add('extend')
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
function open_sidebar() {
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let overlay = document.querySelector('.off-canvas-overlay')
|
||
|
||
sidebar.classList.add('show')
|
||
|
||
overlay.classList.add('show')
|
||
|
||
}
|
||
|
||
function hide_canvas() {
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let overlay = document.querySelector('.off-canvas-overlay')
|
||
|
||
sidebar.classList.remove('show')
|
||
|
||
overlay.classList.remove('show')
|
||
|
||
}
|
||
|
||
|
||
|
||
</script>
|
||
|
||
|
||
|
||
<div class="off-canvas-content">
|
||
|
||
<div class="columns">
|
||
|
||
<div class="column col-12 col-lg-12">
|
||
|
||
<div class="book-navbar">
|
||
|
||
<!-- For Responsive Layout -->
|
||
|
||
<header class="navbar">
|
||
|
||
<section class="navbar-section">
|
||
|
||
<a onclick="open_sidebar()">
|
||
|
||
<i class="icon icon-menu"></i>
|
||
|
||
</a>
|
||
|
||
</section>
|
||
|
||
</header>
|
||
|
||
</div>
|
||
|
||
<div class="book-content" style="max-width: 960px; margin: 0 auto;
|
||
|
||
overflow-x: auto;
|
||
|
||
overflow-y: hidden;">
|
||
|
||
<div class="book-post">
|
||
|
||
<p id="tip" align="center"></p>
|
||
|
||
<div><h1>04 容器操作:得心应手掌握 Docker 容器基本操作</h1>
|
||
|
||
<p>前几天在咱们的社群里看到有同学在讨论,说面试的时候被问到容器和镜像的区别,有同学回答说没什么区别,也许是在开玩笑,不过这两者的区别很大。今天,我们就来看看容器的相关知识,比如什么是容器?容器的生命周期,以及容器常用的操作命令。学完之后你可以对比下与镜像的区别。</p>
|
||
|
||
<h3>容器(Container)是什么?</h3>
|
||
|
||
<p>容器是基于镜像创建的可运行实例,并且单独存在,一个镜像可以创建出多个容器。运行容器化环境时,实际上是在容器内部创建该文件系统的读写副本。 这将添加一个容器层,该层允许修改镜像的整个副本。如图 1 所示。</p>
|
||
|
||
<p><img src="assets/CgqCHl9YmlSAGgF0AABXUH--rM4624.png" alt="image.png" /></p>
|
||
|
||
<p>图1 容器组成</p>
|
||
|
||
<p>了解完容器是什么,接下来我们聊一聊容器的生命周期。</p>
|
||
|
||
<h3>容器的生命周期</h3>
|
||
|
||
<p>容器的生命周期是容器可能处于的状态,容器的生命周期分为 5 种。</p>
|
||
|
||
<ol>
|
||
|
||
<li>created:初建状态</li>
|
||
|
||
<li>running:运行状态</li>
|
||
|
||
<li>stopped:停止状态</li>
|
||
|
||
<li>paused: 暂停状态</li>
|
||
|
||
<li>deleted:删除状态</li>
|
||
|
||
</ol>
|
||
|
||
<p>各生命周期之前的转换关系如图所示:</p>
|
||
|
||
<p><img src="assets/CgqCHl9YmniARFcOAADHTlGkncs129.png" alt="image" /></p>
|
||
|
||
<p>图2 容器的生命周期</p>
|
||
|
||
<p>通过<code>docker create</code>命令生成的容器状态为初建状态,初建状态通过<code>docker start</code>命令可以转化为运行状态,运行状态的容器可以通过<code>docker stop</code>命令转化为停止状态,处于停止状态的容器可以通过<code>docker start</code>转化为运行状态,运行状态的容器也可以通过<code>docker pause</code>命令转化为暂停状态,处于暂停状态的容器可以通过<code>docker unpause</code>转化为运行状态 。处于初建状态、运行状态、停止状态、暂停状态的容器都可以直接删除。</p>
|
||
|
||
<p>下面我通过实际操作和命令来讲解容器各生命周期间的转换关系。</p>
|
||
|
||
<h3>容器的操作</h3>
|
||
|
||
<p>容器的操作可以分为五个步骤:创建并启动容器、终止容器、进入容器、删除容器、导入和导出容器。下面我们逐一来看。</p>
|
||
|
||
<h4>(1)创建并启动容器</h4>
|
||
|
||
<p>容器十分轻量,用户可以随时创建和删除它。我们可以使用<code>docker create</code>命令来创建容器,例如:</p>
|
||
|
||
<pre><code>$ docker create -it --name=busybox busybox
|
||
|
||
Unable to find image 'busybox:latest' locally
|
||
|
||
latest: Pulling from library/busybox
|
||
|
||
61c5ed1cbdf8: Pull complete
|
||
|
||
Digest: sha256:4f47c01fa91355af2865ac10fef5bf6ec9c7f42ad2321377c21e844427972977
|
||
|
||
Status: Downloaded newer image for busybox:latest
|
||
|
||
2c2e919c2d6dad1f1712c65b3b8425ea656050bd5a0b4722f8b01526d5959ec6
|
||
|
||
$ docker ps -a| grep busybox
|
||
|
||
2c2e919c2d6d busybox "sh" 34 seconds ago Created busybox
|
||
|
||
</code></pre>
|
||
|
||
<p>如果使用<code>docker create</code>命令创建的容器处于停止状态,我们可以使用<code>docker start</code>命令来启动它,如下所示。</p>
|
||
|
||
<pre><code>$ docker start busybox
|
||
|
||
$ docker ps
|
||
|
||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||
|
||
d6f3d364fad3 busybox "sh" 16 seconds ago Up 8 seconds busybox
|
||
|
||
</code></pre>
|
||
|
||
<p>这时候我们可以看到容器已经处于启动状态了。
|
||
|
||
容器启动有两种方式:</p>
|
||
|
||
<ol>
|
||
|
||
<li>使用<code>docker start</code>命令基于已经创建好的容器直接启动 。</li>
|
||
|
||
<li>使用<code>docker run</code>命令直接基于镜像新建一个容器并启动,相当于先执行<code>docker create</code>命令从镜像创建容器,然后再执行<code>docker start</code>命令启动容器。</li>
|
||
|
||
</ol>
|
||
|
||
<p>使用<code>docker run</code>的命令如下:</p>
|
||
|
||
<pre><code>$ docker run -it --name=busybox busybox
|
||
|
||
</code></pre>
|
||
|
||
<p>当使用<code>docker run</code>创建并启动容器时,Docker 后台执行的流程为:</p>
|
||
|
||
<ul>
|
||
|
||
<li>Docker 会检查本地是否存在 busybox 镜像,如果镜像不存在则从 Docker Hub 拉取 busybox 镜像;</li>
|
||
|
||
<li>使用 busybox 镜像创建并启动一个容器;</li>
|
||
|
||
<li>分配文件系统,并且在镜像只读层外创建一个读写层;</li>
|
||
|
||
<li>从 Docker IP 池中分配一个 IP 给容器;</li>
|
||
|
||
<li>执行用户的启动命令运行镜像。</li>
|
||
|
||
</ul>
|
||
|
||
<p>上述命令中, -t 参数的作用是分配一个伪终端,-i 参数则可以终端的 STDIN 打开,同时使用 -it 参数可以让我们进入交互模式。 在交互模式下,用户可以通过所创建的终端来输入命令,例如:</p>
|
||
|
||
<pre><code>$ ps aux
|
||
|
||
PID USER TIME COMMAND
|
||
|
||
1 root 0:00 sh
|
||
|
||
6 root 0:00 ps aux
|
||
|
||
</code></pre>
|
||
|
||
<p>我们可以看到容器的 1 号进程为 sh 命令,在容器内部并不能看到主机上的进程信息,因为容器内部和主机是完全隔离的。同时由于 sh 是 1 号进程,意味着如果通过 exit 退出 sh,那么容器也会退出。所以对于容器来说,<strong>杀死容器中的主进程,则容器也会被杀死。</strong></p>
|
||
|
||
<h4>(2)终止容器</h4>
|
||
|
||
<p>容器启动后,如果我们想停止运行中的容器,可以使用<code>docker stop</code>命令。命令格式为 docker stop [-t|--time[=10]]。该命令首先会向运行中的容器发送 SIGTERM 信号,如果容器内 1 号进程接受并能够处理 SIGTERM,则等待 1 号进程处理完毕后退出,如果等待一段时间后,容器仍然没有退出,则会发送 SIGKILL 强制终止容器。</p>
|
||
|
||
<pre><code>$ docker stop busybox
|
||
|
||
busybox
|
||
|
||
</code></pre>
|
||
|
||
<p>如果你想查看停止状态的容器信息,你可以使用 docker ps -a 命令。</p>
|
||
|
||
<pre><code>$ docker ps -a
|
||
|
||
CONTAINERID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||
|
||
28d477d3737a busybox "sh" 26 minutes ago Exited (137) About a minute ago busybox
|
||
|
||
</code></pre>
|
||
|
||
<p>处于终止状态的容器也可以通过<code>docker start</code>命令来重新启动。</p>
|
||
|
||
<pre><code>$ docker start busybox
|
||
|
||
busybox
|
||
|
||
$ docker ps
|
||
|
||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||
|
||
28d477d3737a busybox "sh" 30 minutes ago Up 25 seconds busybox
|
||
|
||
</code></pre>
|
||
|
||
<p>此外,<code>docker restart</code>命令会将一个运行中的容器终止,并且重新启动它。</p>
|
||
|
||
<pre><code>$ docker restart busybox
|
||
|
||
busybox
|
||
|
||
$ docker ps
|
||
|
||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||
|
||
28d477d3737a busybox "sh" 32 minutes ago Up 3 seconds busybox
|
||
|
||
</code></pre>
|
||
|
||
<h4>(3)进入容器</h4>
|
||
|
||
<p>处于运行状态的容器可以通过<code>docker attach</code>、<code>docker exec</code>、<code>nsenter</code>等多种方式进入容器。</p>
|
||
|
||
<ul>
|
||
|
||
<li><strong>使用</strong><code>docker attach</code>命令<strong>进入容器</strong></li>
|
||
|
||
</ul>
|
||
|
||
<p>使用 docker attach ,进入我们上一步创建好的容器,如下所示。</p>
|
||
|
||
<pre><code>$ docker attach busybox
|
||
|
||
/ # ps aux
|
||
|
||
PID USER TIME COMMAND
|
||
|
||
1 root 0:00 sh
|
||
|
||
7 root 0:00 ps aux
|
||
|
||
/ #
|
||
|
||
</code></pre>
|
||
|
||
<p>注意:当我们同时使用<code>docker attach</code>命令同时在多个终端运行时,所有的终端窗口将同步显示相同内容,当某个命令行窗口的命令阻塞时,其他命令行窗口同样也无法操作。
|
||
|
||
由于<code>docker attach</code>命令不够灵活,因此我们一般不会使用<code>docker attach</code>进入容器。下面我介绍一个更加灵活的进入容器的方式<code>docker exec</code></p>
|
||
|
||
<ul>
|
||
|
||
<li><strong>使用 docker exec 命令进入容器</strong></li>
|
||
|
||
</ul>
|
||
|
||
<p>Docker 从 1.3 版本开始,提供了一个更加方便地进入容器的命令<code>docker exec</code>,我们可以通过<code>docker exec -it CONTAINER</code>的方式进入到一个已经运行中的容器,如下所示。</p>
|
||
|
||
<pre><code>$ docker exec -it busybox sh
|
||
|
||
/ # ps aux
|
||
|
||
PID USER TIME COMMAND
|
||
|
||
1 root 0:00 sh
|
||
|
||
7 root 0:00 sh
|
||
|
||
12 root 0:00 ps aux
|
||
|
||
</code></pre>
|
||
|
||
<p>我们进入容器后,可以看到容器内有两个<code>sh</code>进程,这是因为以<code>exec</code>的方式进入容器,会单独启动一个 sh 进程,每个窗口都是独立且互不干扰的,也是使用最多的一种方式。</p>
|
||
|
||
<h4>(4)删除容器</h4>
|
||
|
||
<p>我们已经掌握了用 Docker 命令创建、启动和终止容器。那如何删除处于终止状态或者运行中的容器呢?删除容器命令的使用方式如下:<code>docker rm [OPTIONS] CONTAINER [CONTAINER...]</code>。</p>
|
||
|
||
<p>如果要删除一个停止状态的容器,可以使用<code>docker rm</code>命令删除。</p>
|
||
|
||
<pre><code>docker rm busybox
|
||
|
||
</code></pre>
|
||
|
||
<p>如果要删除正在运行中的容器,必须添加 -f (或 --force) 参数, Docker 会发送 SIGKILL 信号强制终止正在运行的容器。</p>
|
||
|
||
<pre><code>docker rm -f busybox
|
||
|
||
</code></pre>
|
||
|
||
<h4>(5)导出导入容器</h4>
|
||
|
||
<ul>
|
||
|
||
<li><strong>导出容器</strong></li>
|
||
|
||
</ul>
|
||
|
||
<p>我们可以使用<code>docker export CONTAINER</code>命令导出一个容器到文件,不管此时该容器是否处于运行中的状态。导出容器前我们先进入容器,创建一个文件,过程如下。</p>
|
||
|
||
<p>首先进入容器创建文件</p>
|
||
|
||
<pre><code>docker exec -it busybox sh
|
||
|
||
cd /tmp && touch test
|
||
|
||
</code></pre>
|
||
|
||
<p>然后执行导出命令</p>
|
||
|
||
<pre><code>docker export busybox > busybox.tar
|
||
|
||
</code></pre>
|
||
|
||
<p>执行以上命令后会在当前文件夹下生成 busybox.tar 文件,我们可以将该文件拷贝到其他机器上,通过导入命令实现容器的迁移。</p>
|
||
|
||
<ul>
|
||
|
||
<li><strong>导入容器</strong></li>
|
||
|
||
</ul>
|
||
|
||
<p>通过<code>docker export</code>命令导出的文件,可以使用<code>docker import</code>命令导入,执行完<code>docker import</code>后会变为本地镜像,最后再使用<code>docker run</code>命令启动该镜像,这样我们就实现了容器的迁移。</p>
|
||
|
||
<p>导入容器的命令格式为 docker import [OPTIONS] file|URL [REPOSITORY[:TAG]]。接下来我们一步步将上一步导出的镜像文件导入到其他机器的 Docker 中并启动它。</p>
|
||
|
||
<p>首先,使用<code>docker import</code>命令导入上一步导出的容器</p>
|
||
|
||
<pre><code>docker import busybox.tar busybox:test
|
||
|
||
</code></pre>
|
||
|
||
<p>此时,busybox.tar 被导入成为新的镜像,镜像名称为 busybox:test 。下面,我们使用<code>docker run</code>命令启动并进入容器,查看上一步创建的临时文件</p>
|
||
|
||
<pre><code>docker run -it busybox:test sh
|
||
|
||
/ # ls /tmp/
|
||
|
||
test
|
||
|
||
</code></pre>
|
||
|
||
<p>可以看到我们之前在 /tmp 目录下创建的 test 文件也被迁移过来了。这样我们就通过<code>docker export</code>和<code>docker import</code>命令配合实现了容器的迁移。</p>
|
||
|
||
<h3>结语</h3>
|
||
|
||
<p>到此,我相信你已经了解了容器的基本概念和组成,并已经熟练掌握了容器各个生命周期操作和管理。那容器与镜像的区别,你应该也很清楚了。镜像包含了容器运行所需要的文件系统结构和内容,是静态的只读文件,而容器则是在镜像的只读层上创建了可写层,并且容器中的进程属于运行状态,容器是真正的应用载体。</p>
|
||
|
||
<p>那你知道为什么容器的文件系统要设计成写时复制(如图 1 所示),而不是每一个容器都单独拷贝一份镜像文件吗?思考后,可以把你的想法写在留言区。</p>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div>
|
||
|
||
<div style="float: left">
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/03 镜像使用:Docker 环境下如何配置你的镜像?.md.html">上一页</a>
|
||
|
||
</div>
|
||
|
||
<div style="float: right">
|
||
|
||
<a href="/专栏/由浅入深吃透 Docker-完/05 仓库访问:怎样搭建属于你的私有仓库?.md.html">下一页</a>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||
|
||
</div>
|
||
|
||
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70997b3ffa373cfa","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
|
||
|
||
</body>
|
||
|
||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||
|
||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
|
||
|
||
<script>
|
||
|
||
window.dataLayer = window.dataLayer || [];
|
||
|
||
|
||
|
||
function gtag() {
|
||
|
||
dataLayer.push(arguments);
|
||
|
||
}
|
||
|
||
|
||
|
||
gtag('js', new Date());
|
||
|
||
gtag('config', 'G-NPSEEVD756');
|
||
|
||
var path = window.location.pathname
|
||
|
||
var cookie = getCookie("lastPath");
|
||
|
||
console.log(path)
|
||
|
||
if (path.replace("/", "") === "") {
|
||
|
||
if (cookie.replace("/", "") !== "") {
|
||
|
||
console.log(cookie)
|
||
|
||
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
setCookie("lastPath", path)
|
||
|
||
}
|
||
|
||
|
||
|
||
function setCookie(cname, cvalue) {
|
||
|
||
var d = new Date();
|
||
|
||
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
|
||
|
||
var expires = "expires=" + d.toGMTString();
|
||
|
||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||
|
||
}
|
||
|
||
|
||
|
||
function getCookie(cname) {
|
||
|
||
var name = cname + "=";
|
||
|
||
var ca = document.cookie.split(';');
|
||
|
||
for (var i = 0; i < ca.length; i++) {
|
||
|
||
var c = ca[i].trim();
|
||
|
||
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
|
||
|
||
}
|
||
|
||
return "";
|
||
|
||
}
|
||
|
||
|
||
|
||
</script>
|
||
|
||
|
||
|
||
</html>
|
||
|