何久 發表於 2018-5-1 12:49:00

Docker初体验

<p>断断续续的使用Docker好几年了,但是一直没有全面深入的去了解过,每次用到都是Google一下相关的命令解决临时的问题,到头来却毫无收获。好在,我终于意识到了这个问题,便决定从头开始,耐心的学学Docker,并把学习过程记录下来,方便以后参考,也望与大家交流学习。</p>
<blockquote>
<p>本人比较偏爱<strong>Ubuntu</strong>,故本文所用命令皆基于Ubuntu 16.04,其他版本的命令会有稍有不同,本文不多做介绍。</p>
</blockquote>
<p><strong>目录</strong></p>
<ol>
<li>简介
<ul>
<li>容器 VS 虚拟机</li>
</ul>
</li>
<li>安装
<ul>
<li>准备</li>
<li>安装</li>
<li>镜像加速</li>
<li>安装Docker Compose</li>
</ul>
</li>
<li>常用命令
<ul>
<li>运行容器</li>
<li>管理容器</li>
<li>镜像管理</li>
</ul>
</li>
<li>Dockerfile
<ul>
<li>OnBuild</li>
<li>Ignore File</li>
</ul>
</li>
</ol>
<h2 id="简介">简介</h2>
<p>容器:将软件打包成标准化单元,以用于开发、交付和部署,而 Docker 是世界领先的软件容器平台。</p>
<p>容器镜像是轻量的、可执行的独立软件包,包含软件运行所需的所有内容:代码、运行时环境、系统工具、系统库和设置。</p>
<h3 id="容器-vs-虚拟机">容器 VS 虚拟机:</h3>
<p>容器和虚拟机具有相似的资源隔离和分配优势,但功能有所不同,因为容器虚拟化的是操作系统,而不是硬件,因此容器更容易移植,效率也更高。</p>
<ul>
<li>
<p>容器是一个应用层抽象,用于将代码和依赖资源打包在一起。多个容器可以在同一台机器上运行,共享操作系统内核,但各自作为独立的进程在用户空间中运行。与虚拟机相比,容器占用的空间较少(容器镜像大小通常只有几十兆),瞬间就能完成启动。</p>
</li>
<li>
<p>虚拟机 (VM) 是一个物理硬件层抽象,用于将一台服务器变成多台服务器。管理程序允许多个 VM 在一台机器上运行。每个 VM 都包含一整套操作系统、一个或多个应用、必要的二进制文件和库资源,因此占用大量空间。而且 VM 启动也十分缓慢。</p>
</li>
</ul>
<p><img src="https://images2018.cnblogs.com/blog/347047/201804/347047-20180428002728376-1167437176.png" alt="container-vm" loading="lazy"></p>
<h2 id="安装">安装</h2>
<h3 id="准备">准备</h3>
<p>首先更新Package索引:</p>
<pre><code class="language-bash">sudo apt-get update
</code></pre>
<p>添加Https支持:</p>
<pre><code class="language-bash">sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common -y
</code></pre>
<p>然后添加Docker官方的GPG key:</p>
<pre><code class="language-bash">curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

## 如果上面的地址不能下载,可以使用国内镜像
curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg| sudo apt-key add -
</code></pre>
<p>添加Docker-CE稳定版仓储地址:</p>
<pre><code class="language-bash">sudo add-apt-repository \
   "deb https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
</code></pre>
<p>由于Docker官方仓储<code>download.docker.com</code>的访问较慢,故使用了中科大镜像源替代。</p>
<h3 id="安装-1">安装</h3>
<p>最后,便可以直接安装了:</p>
<pre><code class="language-bash">sudo apt-get update
sudo apt-get install docker-ce
</code></pre>
<p>我们可以运行一下<code>Hello Word</code>来验证一下是否安装成功:</p>
<pre><code class="language-bash">sudo docker run hello-world
</code></pre>
<p>默认情况下,Docker需要使用root身份来访问,每次都使用<code>sudo</code>命令较为麻烦,我们可以将当前用户添加到<code>docker</code>用户组来实现非root用户访问:</p>
<pre><code class="language-bash">sudo usermod -aG docker $USER
</code></pre>
<p>重新登录一下,便可以不使用<code>sudo</code>命令来操作docker了。</p>
<h3 id="镜像加速">镜像加速</h3>
<p>默认情况下,Docker镜像是从Docker官方市场<code>store.docker.com</code>来拉取的,同样非常缓慢,好在Docker官方提供了国内镜像库,可使用如下命令来配置:</p>
<pre><code class="language-bash">docker --registry-mirror=https://registry.docker-cn.com daemon
</code></pre>
<p>为了永久性保留更改,可以修改<code>/etc/docker/daemon.json</code>文件并添加上 registry-mirrors 键值:</p>
<pre><code class="language-bash">{
"registry-mirrors": ["https://registry.docker-cn.com"]
}
</code></pre>
<p>修改保存后重启 Docker 以使配置生效:</p>
<pre><code class="language-bash">sudo systemctl restart docker
</code></pre>
<h3 id="安装docker-compose">安装Docker Compose</h3>
<p>Docker Compose 是一个用来定义和运行复杂应用的Docker工具。我们的应用通常会由多个容器组成,使用Docker Compose可以非常容易的将一组容器当成一个整体来配置部署。</p>
<pre><code class="language-bash">curl -L https://github.com/docker/compose/releases/download/1.23.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
</code></pre>
<p>可以在 https://github.com/docker/compose/releases 查看具体的发布列表。</p>
<h2 id="常用命令">常用命令</h2>
<h3 id="运行容器run">运行容器(run)</h3>
<p>run是我们最常用的命令:</p>
<pre><code class="language-bash">docker run nginx
</code></pre>
<p>如上,便启动了一个<code>nginx</code>容器。</p>
<h4 id="端口映射-p">端口映射(-p)</h4>
<p>此时,我们还无法通过访问宿主机的IP来访问刚才部署的Nginx,需要先进行端口映射:</p>
<pre><code class="language-bash">docker run -p 8080:80 nginx
</code></pre>
<h4 id="后台运行-d">后台运行(-d)</h4>
<p>默认情况下,当我们推出命令行时,容器也会被关闭。我们可以使用<code>-d</code>参数使容器保持后台运行:</p>
<pre><code class="language-bash">docker run -d &lt;image-name&gt;
</code></pre>
<p>然后访问宿主机的IP:8080,便可以看到“Welcome to nginx!”。</p>
<h4 id="指定名称-n">指定名称(-n)</h4>
<pre><code class="language-bash">docker run --name &lt;container-name&gt; &lt;image-name&gt;

docker run --name myredis redis
</code></pre>
<p>如上,创建了一个名称为<code>redis</code>的容器。</p>
<h4 id="持久化数据-v">持久化数据(-v)</h4>
<p>容器被设计为无状态的,当我们删除一个容器时,保存在其中的数据也会随之删除。如果我们希望某些数据不随着容器的删除而删除,则可以使用目录绑定(通常称为卷),将容器中的某个文件夹于主机上的文件夹绑定,来实现数据的持久化。</p>
<pre><code class="language-bash">docker run -v &lt;host-dir&gt;:&lt;container-dir&gt; &lt;image-name&gt;
</code></pre>
<p>除此之外,我们还可以使用<code>Data Containers</code>来实行数据的持久化,数据容器(Data Containers)唯一的职责就是存储和管理数据:</p>
<pre><code class="language-bash">docker create -v /config --name dataContainer busybox
</code></pre>
<p>如上,我们使用<code>busybox</code>镜像创建了一个数据容器,并使用<code>-v</code>参数来指定容器存储和管理数据的目录位置。</p>
<p>然后我们可以将文件拷贝到容器中:</p>
<pre><code class="language-bash">docker cp config.conf dataContainer:/config/
</code></pre>
<p>接下来,我们就可以在新的容器中引用该数据容器了:</p>
<pre><code class="language-bash">docker run --volumes-from dataContainer ubuntu
</code></pre>
<p>新创建的<code>ubuntu</code>容器挂载了数据容器的<code>/config</code>目录。</p>
<h4 id="重启策略--restart">重启策略(--restart)</h4>
<p>通过<code>--restart</code>选项,可以设置容器的重启策略,以决定在容器退出时Docker守护进程是否重启刚刚退出的容器。</p>
<pre><code class="language-bash">docker run -d --restart=always &lt;image-name&gt;
</code></pre>
<p>有如下4种重启策略:</p>
<ul>
<li>no,默认策略,在容器退出时不重启容器</li>
<li>on-failure,在容器非正常退出时(退出状态非0),才会重启容器
<ul>
<li>on-failure:3,在容器非正常退出时重启容器,最多重启3次</li>
</ul>
</li>
<li>always,在容器退出时总是重启容器</li>
<li>unless-stopped,在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止了的容器</li>
</ul>
<h4 id="进入交互模式-it">进入交互模式(-it)</h4>
<pre><code class="language-bash">docker run -it /bin/bash
</code></pre>
<ul>
<li>-i interact 进入交互模式。</li>
<li>-t tty 分配一个伪终端。</li>
</ul>
<p>执行之后,可以看到命令行的主机名已经变成了容器的Id,表示成功进入到了容器中,可以使用<code>exit</code>命令退出容器。</p>
<h4 id="其他">其他</h4>
<pre><code class="language-bash"># 启动一个SQLServer容器
docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Qwer1234' -p 1433:1433 -d --restart=unless-stopped microsoft/mssql-server-linux
</code></pre>
<h3 id="管理容器">管理容器</h3>
<h4 id="查看容器ps">查看容器(ps)</h4>
<pre><code class="language-bash">docker ps
</code></pre>
<p>通过<code>ps</code>命令可以看到当前运行的容器,添加<code>-a</code>参数,则可以看到停止的容器。</p>
<p>我们可以使用<code>docker inspect &lt;friendly-name|container-id&gt;</code>来查看某个容器的详细信息:</p>
<pre><code class="language-bash">dokcer inspect redis
</code></pre>
<h4 id="附加容器attach">附加容器(attach)</h4>
<p>ttach可以附加到一个已经运行的容器的stdin中。</p>
<pre><code class="language-bash">docker attach
</code></pre>
<h4 id="进入容器exec">进入容器(exec)</h4>
<pre><code class="language-bash">docker exec -it /bin/bash
</code></pre>
<p>是需要注意的是,对于<code>attach</code>,如果从这个stdin中exit,会导致容器的停止。而<code>exec</code>则不会,推荐使用<code>exec</code>。</p>
<h4 id="停止容器stop">停止容器(stop)</h4>
<pre><code class="language-bash">docker stop
</code></pre>
<h4 id="删除容器rm">删除容器(rm)</h4>
<pre><code class="language-bash">docker rm
</code></pre>
<p>如果要删除的容器正在运行,则无法删除,可以添加<code>-f</code>参数来强制删除,也可以先停止容器再删除:</p>
<p>如果我们想删除所有的容器,可以使用如下命令:</p>
<pre><code class="language-bash">docker rm $(docker ps -a -q) -f
</code></pre>
<h3 id="镜像管理">镜像管理</h3>
<p>Docker把应用程序及其运行环境等打包在 image 文件里面,相当于容器的模板。</p>
<h4 id="搜索镜像">搜索镜像</h4>
<p>我们可以在 registry.hub.docker.com 查找镜像,也可以使用 <code>dokcer search &lt;name&gt;</code> 命令来搜索,如:我们使用如下命令来搜索<code>redis</code>镜像。</p>
<pre><code class="language-bash">docker search redis
</code></pre>
<h4 id="查看镜像">查看镜像</h4>
<pre><code class="language-bash"># 查看镜像列表
docker images

# 查看所有镜像(包括中间层镜像)
docker image -a

# 查看所有镜像的ID
docker images -q

# 查看所有的虚悬镜像(-f 显示满足条件的镜像)
docker images -f "dangling=true"

# 按仓库名过滤
docker images

# 按仓库名和标签过滤
docker images
</code></pre>
<p>镜像列表输出如下:</p>
<table>
<thead>
<tr>
<th>REPOSITORY</th>
<th>TAG</th>
<th>IMAGE ID</th>
<th>CREATED</th>
<th>SIZE</th>
</tr>
</thead>
<tbody>
<tr>
<td>hello-world</td>
<td>latest</td>
<td>e38bc07ac18e</td>
<td>2 weeks ago</td>
<td>1.85kB</td>
</tr>
</tbody>
</table>
<p>每列含义:</p>
<ul>
<li>REPOSITORY:仓储名</li>
<li>TAG:标签, 一个镜像可以有多个标签</li>
<li>IMAGE ID:镜像的唯一标识,通常在删除镜像时使用</li>
<li>CREATED:创建时间</li>
<li>SIZE:所占用的空间,展开后的各层所占空间的总和。</li>
</ul>
<h4 id="删除镜像">删除镜像</h4>
<pre><code class="language-bash"># 删除镜像
docker rmi

docker image rm

# 删除所有镜像
docker image rm $(docker images -q) -f

# 删除虚悬镜像(dangling image)
docker image prune
</code></pre>
<p>仓库名和标签均为<code>&lt;none&gt;</code>,这类无标签、无仓储名的镜像被称为<code>dangling image</code>。</p>
<h4 id="拉取推送">拉取推送</h4>
<pre><code class="language-bash"># 拉取镜像
docker pull

# 构建镜像
docker build

# 推送镜像
docker push
</code></pre>
<h4 id="其他-1">其他</h4>
<pre><code class="language-bash"># 查看镜像、容器、卷占用的空间
docker system df
</code></pre>
<h2 id="dockerfile">Dockerfile</h2>
<p>Dcoker镜像是从一个基础镜像开始的,基础镜像包括应用程序所需的平台依赖项, 例如, 安装了<code>JVM</code>或<code>CLR</code>等。</p>
<p>镜像的定义是使用<code>dockerfile</code>文件来表达的。<code>dockerfile</code>是描述如何部署应用的列表。一个简单的<code>Dockerfile</code>文件如下:</p>
<pre><code class="language-dockerfile">FROM nginx:alpine
COPY . /usr/share/nginx/html
</code></pre>
<p>如上,我们的基础镜像是一个alpine版本的<code>nginx</code>,从而拥有了一个安装了<code>nginx</code>的linux环境。</p>
<p>接下来,我们可以通过定义的<code>dockerfile</code>文件来构建镜像:</p>
<pre><code class="language-bash">docker build -t webserver-image:v1 .
</code></pre>
<p>其<code>-t</code>参数为镜像指定一个友好的名字和标记,<code>.</code>则表示使用当前目录的<code>dockerfile</code>文件。</p>
<h3 id="onbuild">OnBuild</h3>
<p>通常,<code>dockerfile</code>文件的执行顺序是从上到下,但我们可以使用<code>ONBUILD</code>指令来延后执行(在子镜像构建时执行)。</p>
<p>如下,我们定义一个经典的<code>Node</code>应用程序基础镜像:</p>
<pre><code class="language-dockerfile">FROM node:10
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
ONBUILD COPY package.json /usr/src/app/
ONBUILD RUN npm install
ONBUILD COPY . /usr/src/app
CMD [ "npm", "start" ]
</code></pre>
<p>当我们构建该镜像时,<code>ONBUILD</code>指令包含的内容将不会执行,然后我们定义一个该镜像的子镜像:</p>
<pre><code class="language-dockerfile">FROM node:10-onbuild
EXPOSE 3000
</code></pre>
<p>当我们构建该镜像时,上面的<code>ONBUILD</code>才会被执行。这样做的优势是可以在多个镜像中共享一份基础镜像,大大减少构建的速度。</p>
<h3 id="ignore-file">Ignore File</h3>
<p>为了防止将一个不必要或者敏感的数据打包到镜像中,可以使用<code>.dockerignore</code>文件进行配置。</p>
<p>下面的命令将<code>passwords.txt</code>文件加到了忽略中,确保它不会意外的被打包到镜像中发布出去。</p>
<pre><code class="language-bash">echo passwords.txt &gt;&gt; .dockerignore
</code></pre>
<p>我们可以将<code>.dockerignore</code>文件存储在源代码管理中,保持团队间的一致。</p>
<h2 id="总结">总结</h2>
<p>Docker是革命性的,干净利落的UX俘获了技术人员的芳心,ASP.NET Core 也是全面拥抱Docker,我们也要紧跟时代的步伐。</p>
<p>本文主要介绍docker的一些基本用法,可作为一个docker使用笔记来参考,并不断的补充完善,但不会涉及到比较深入的介绍,后续在其他文章中会详细介绍一些具体的用法。</p><br><br>
来源:https://www.cnblogs.com/RainingNight/p/first-docker-note.html
頁: [1]
查看完整版本: Docker初体验