張浩 發表於 2016-7-3 18:56:00

Docker学习笔记

<p>Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。</p>
<p>官网:https://www.docker.com/<br>
相关资料:<br>
1、Docker入门教程 http://dockone.io/article/111<br>
2、Docker_百度百科 http://baike.baidu.com/view/11854949.htm<br>
3、史上最全Docker资料集粹 http://special.csdncms.csdn.net/BeDocker/<br>
4、Docker - 话题精华 - 知乎 http://www.zhihu.com/topic/19950993/top-answers<br>
5、docker 简明教程 | 简果网 http://www.simapple.com/docker-tutorial<br>
6、如何使用Dockerfile构建镜像 http://blog.csdn.net/qinyushuang/article/details/43342553<br>
7、Dockerfile reference - Docker https://docs.docker.com/engine/reference/builder/</p>
<h2 id="docker与虚拟机比较">Docker与虚拟机比较</h2>
<p>作为一种轻量级的虚拟化方式,Docker在运行应用上跟传统的虚拟机方式相比具有显著优势:</p>
<ul>
<li>Docker容器很快,启动和停止可以在秒级实现,这相比传统的虚拟机方式要快得多。</li>
<li>Docker容器对系统资源需求很少,一台主机上可以同时运行数千个Docker容器。</li>
<li>Docker通过类似Git的操作来方便用户获取、分发和更新应用镜像,指令简明,学习成本较低。</li>
<li>Docker通过Dockerfile配置文件来支持灵活的自动化创建和部署机制,提高工作效率。</li>
</ul>
<p><img src="https://images2015.cnblogs.com/blog/663847/201607/663847-20160703190439265-1566952969.jpg" alt="" loading="lazy"></p>
<p>(本段摘自《Docker技术入门与实战》)</p>
<p>虚拟机实现了硬件上的虚拟,而Docker则实现了操作系统级别的虚拟。</p>
<h2 id="安装">安装</h2>
<p>Docker 要求 Ubuntu 系统的内核版本高于 3.10 ,通过 uname -r 命令查看你当前的内核版本:</p>
<pre><code>#uname -r
3.10.0-327.22.2.el7.x86_64
</code></pre>
<p>Docker支持以下的CentOS版本:</p>
<ul>
<li>CentOS 7 (64-bit)</li>
<li>CentOS 6.5 (64-bit) 或更高的版本</li>
</ul>
<p>Docker 支持以下的 Ubuntu 版本:</p>
<ul>
<li>Ubuntu Precise 12.04 (LTS)</li>
<li>Ubuntu Trusty 14.04 (LTS)</li>
<li>Ubuntu Wily 15.10</li>
<li>其他更新的版本……</li>
</ul>
<h3 id="linux安装">Linux安装</h3>
<pre><code class="language-shell">curl -fsSL https://get.docker.com/ | sh

# daocloud.io 国内镜像
curl -sSL https://get.daocloud.io/docker | sh
</code></pre>
<p>该安装包适用于 Ubuntu,Debian,Centos 等大部分主流 Linux 发行版。</p>
<p>当以普通用户身份去使用<code>docker images</code>时,如果出现以下错误:</p>
<pre><code>Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.26/images/json: dial unix /var/run/docker.sock: connect: permission denied
</code></pre>
<p>是因为权限问题:</p>
<pre><code>sudo groupadd docker
sudo gpasswd -a ${USER} docker
sudo service docker restart
newgrp - docker
</code></pre>
<p>CentOS7支持使用yum安装:</p>
<pre><code>yum update
yum install docker
</code></pre>
<p>查看文档:<br>
https://docs.docker.com/engine/installation/linux/centos/<br>
http://docs.daocloud.io/faq/install-docker-daocloud</p>
<p>查看版本:</p>
<pre><code class="language-shell">docker version
</code></pre>
<p>显示:</p>
<pre><code class="language-shell">Client:
Version:      1.11.2
API version:1.23
Go version:   go1.5.4
Git commit:   b9f10c9
Built:      Wed Jun1 21:23:11 2016
OS/Arch:      linux/amd64

Server:
Version:      1.11.2
API version:1.23
Go version:   go1.5.4
Git commit:   b9f10c9
Built:      Wed Jun1 21:23:11 2016
OS/Arch:      linux/amd64
</code></pre>
<p>启动docker服务:</p>
<pre><code>service docker start

# 或者
systemctl start docker
</code></pre>
<p>centos7使用systemctl 替代service 管理服务。systemctl 常见用法:</p>
<pre><code># 格式
systemctl   动作   服务名.service

# 常见命令
systemctl start docker #启动
systemctl restart docker #重启
systemctl stop docker #停止
systemctl status docker #查看状态
systemctl enable docker #自启动
systemctl disable docker #禁止自启动
</code></pre>
<p>.service可以省略。<br>
(详见:RHEL7中systemctl的用法 http://blog.csdn.net/catoop/article/details/47318225)</p>
<p>为了后面的需要,我们这里下载个ubuntu的镜像:</p>
<pre><code class="language-shell">docker search ubuntu
docker pull ubuntu

# 查看所有可用镜像
docker images -a
</code></pre>
<p>这就下载了最新的ubuntu系统镜像到本地,接下来我们可以从该镜像创建多个容器。具体命令含义下面会有说明。</p>
<p>Docker里比较重要的概念有注册服务器、仓库、镜像、容器。</p>
<p><strong>仓库:</strong> 注册服务器是存放仓库的地方,其上往往存放着多个仓库。每个仓库集中存放某一类镜像,往往包括多个镜像文件,通过不同的标签(tag)来进行区分。例如存放Ubuntu操作系统镜像的仓库,称为Ubuntu仓库,其中可能包括14.04、12.04等不同版本的镜像。</p>
<p><strong>镜像:</strong> Docker镜像(Image)类似于虚拟机镜像,可以将它理解为一个面向Docker引擎的只读模板,包含了文件系统。例如:一个镜像可以只包含一个完整的Ubuntu操作系统环境,可以把它称为一个Ubuntu镜像。</p>
<p><strong>容器:</strong> 容器是从镜像创建的应用运行实例,可以将其启动、开始、停止、删除,而这些容器都是相互隔离、互不可见的。可以从一个镜像创建无数个容器。平时我们主要操作的就是容器。我们也可以把容器打包成镜像以方便再次使用。镜像自身是只读的。容器从镜像启动的时候,Docker会在镜像的最上层创建一个可写层,镜像本身将保持不变。</p>
<h2 id="客户端和守护进程">客户端和守护进程</h2>
<p>这部分将介绍docker的结构以及docker服务的管理。</p>
<h3 id="docker-的-cs-模式">Docker 的 C/S 模式</h3>
<p>docker是C/S架构,使用client与Server通信。</p>
<p>支持三种连接方式:<br>
unix:///var/run/docker.sock<br>
tcp://host:port<br>
fd://socketfd</p>
<h3 id="docker-守护进程的配置和操作">Docker 守护进程的配置和操作</h3>
<p>使用<code>ps -ef | grep docker</code>查看docker进程。</p>
<p>管理docker服务:</p>
<pre><code class="language-shell">service docker start
service docker stop
service docker restart
</code></pre>
<p>如使用<code>service docker start</code>实际上是执行了<code>/bin/systemctl startdocker.service</code>命令。<br>
建议重启使用:</p>
<pre><code class="language-shell">systemctl daemon-reload
systemctl restart docker.service
</code></pre>
<p>docker守护进程的配置和操作模式:</p>
<pre><code>docker -d
</code></pre>
<p>-d 以后台方式运行容器。</p>
<p>下面是容器创建时的一些配置,按需添加。初学者可以简单看看,以后需要再来查找。</p>
<p>运行相关:</p>
<pre><code class="language-shell"> -D, --debug=false
-e,--exec-driver="native"
-p,--pidfile="/var/run/docker.pid"
</code></pre>
<p>服务器相关:</p>
<pre><code class="language-shell"> -G,--group="docker"
-H,--host=[]
--tls=false
</code></pre>
<p>RemoteAPI相关:</p>
<pre><code class="language-shell">        --api-enable-cors=false
</code></pre>
<p>存储相关:</p>
<pre><code class="language-shell"> -S,--storage-driver=""
--selinux-enabled=false
--storage-opt=[]
</code></pre>
<p>网络设置相关:</p>
<pre><code class="language-shell"> -b,--bridge="" 设置自定义网桥
--bip=""
--dns=[]
--ip=0.0.0.0
</code></pre>
<h3 id="启动配置文件">启动配置文件</h3>
<p>Ubuntu: /etc/default/docker<br>
CentOS: /etc/sysconfig/docker</p>
<p>如果没有配置文件,可以直接编辑:</p>
<pre><code class="language-shell">vim/lib/systemd/system/docker.service
</code></pre>
<p>里面的ExecStart就是启动配置,默认是:</p>
<pre><code class="language-shell">ExecStart=/usr/bin/docker -H fd://
</code></pre>
<p>我们可以加几个配置:</p>
<pre><code class="language-shell">ExecStart=/usr/bin/docker -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock -H fd:// --label name=server_1
</code></pre>
<p>然后重启:</p>
<pre><code class="language-shell">systemctl daemon-reload
systemctl restart docker.service

# 如果出问题了,可以使用下面命令查看:
systemctl status docker.service
</code></pre>
<p>通过<code>ps -ef | grep docker</code>可以查看刚才添加的信息:</p>
<pre><code class="language-shell"># ps -ef | grep docker
root      8262   10 23:50 ?      00:00:00 /usr/bin/docker daemon -H tcp://0.0.0.0:4243 -H unix:///var/run/docker.sock -H fd:// --label name=server_1
</code></pre>
<blockquote>
<p>解决centos7和docker1.9没有配置文件问题 - 建站 - IT精英团<br>
http://www.itnpc.com/news/web/145083113731628.html</p>
</blockquote>
<h3 id="docker-的远程访问">Docker 的远程访问</h3>
<p>我们可以从一台安装了docker的机器访问另一台安装了docker的机器。一般情况下我们使用当前机器的docker客户端访问当前机器的Server端。下面演示如何访问其他docker服务端。</p>
<p>第一台IP:192.168.12.3<br>
第二台IP:192.168.12.4</p>
<p>使用第二台安装有docker的服务器做演示。为区分,设置label不同。</p>
<p>修改守护进程(Server)默认的启动配置:<br>
默认是:-H fd://<br>
可修改为:-H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock -H fd:// --label name=server_1</p>
<p>可设置多个连接方式。</p>
<p>第一台访问第二台机器的docker服务:</p>
<ul>
<li>通过http连接Server:</li>
</ul>
<pre><code class="language-shell">curl http://192.168.12.4:2375/info
</code></pre>
<p>访问的是服务器192.168.12.4:2375的info接口,返回服务器相关信息。</p>
<ul>
<li>通过docker客户端访问Server:</li>
</ul>
<pre><code class="language-shell">docker -H tcp://192.168.12.4:2375 info
</code></pre>
<p>如果是是第一台机器访问第一台机器Docker的服务端,则使用127.0.0.1:2375就行了。</p>
<p>和服务器端一样,客户端也支持三种连接方式,默认是 <code>-H unix:///var/run/docker.sock</code>:<br>
-Hunix:///path/to/sock<br>
tcp://host:port<br>
fd://socketfd</p>
<p>docker客户端使用<code>docker info</code>默认访问的是本地Server。可以修改环境变量DOCKER_HOST改变默认连接。命令行直接输入:</p>
<pre><code class="language-shell">export DOCKER_HOST="tcp://127.0.0.1:2375"
</code></pre>
<p>127.0.0.1:237可以替换为实际的Server地址。</p>
<p>如果想恢复本地连接,将DOCKER_HOST置空即可:</p>
<pre><code class="language-shell">export DOCKER_HOST=""
</code></pre>
<h2 id="docker容器">Docker容器</h2>
<h3 id="容器的基本操作">容器的基本操作</h3>
<p>我们可以从镜像中创建容器。</p>
<pre><code>Docker run IMAGE 在新的容器中执行命令
</code></pre>
<p>该命令每运行一次,就创建了一个新的容器。下面演示从下载好的ubuntu镜像中创建并运行一个新的容器:</p>
<pre><code class="language-shell"># 只运行一次命令
docker run ubuntu echo 'hello world' 运行一个新的容器,并执行命令echo

# 创建并运行容器,然后进入容器
docker run -i -t--name test ubuntu /bin/bash                        以交互式终端运行一个新的容器,镜像是ubuntu,使用bash,容器别名test
</code></pre>
<p>-i 交互式界面,默认是false<br>
-t 伪终端,默认false<br>
--name 容器别名,默认随机命名</p>
<p>exit 退出交互式界面,容器停止运行<br>
Crtl+P 或者Crtl+Q 退出交互式界面,容器在后台运行。(注意是大写P和Q)</p>
<p>查看容器:</p>
<pre><code class="language-shell">docker ps                        查看正在运行的容器
docker ps -a查看所有容器
docker ps -l查看最近一次运行的容器
</code></pre>
<p>示例:</p>
<pre><code class="language-shell"># docker ps -a
CONTAINER ID      IMAGE                     COMMAND                  CREATED             STATUS                     PORTS               NAMES
8c52c83c1903      redis                     "docker-entrypoint.sh"   2 hours ago         Exited (0) 2 hours ago                         myredis
</code></pre>
<p>容器操作:</p>
<pre><code class="language-shell">docker create 容器名或者容器ID        创建容器
docker start [-i] 容器名                启动容器
docker run 容器名或者容器ID        运行容器,相当于docker create + docker start
docker attach 容器名或者容器ID        进入容器的命令行
docker stop 容器名                                                         停止容器
docker rm 容器名                                                           删除容器

docker top 容器名                        查看WEB应用程序容器的进程
docker inspect 容器名 查看Docker的底层信息
</code></pre>
<p>删除容器时,容器必须是停止状态,否则会报错误。</p>
<h3 id="守护式容器">守护式容器</h3>
<p>我们可以使用守护式容器运行一个或者多个服务,例如运行lamp服务、redis服务、mysql服务等。</p>
<p>什么是守护式容器?</p>
<ul>
<li>能够长期运行</li>
<li>没有交互式会话</li>
<li>适合运行应用程序和服务</li>
</ul>
<p>启动守护式容器:</p>
<pre><code class="language-shell">docker run -d IMAGE
</code></pre>
<p>-d 让容器在后台运行</p>
<p>后台运行任务:</p>
<pre><code class="language-shell">docker run -d --name d1 ubuntu /bin/sh -c "while true;do echo hello world;sleep 1;done;"
b89b9ce64d34bd202a642c8190428f4776f15e882f138949259722f22120201a
</code></pre>
<p>返回了一个守护进程的唯一ID。</p>
<p>查看守护进程的运行情况:</p>
<pre><code class="language-shell"># docker ps
CONTAINER ID      IMAGE                     COMMAND                  CREATED             STATUS            PORTS               NAMES
b89b9ce64d34      ubuntu                      "/bin/sh -c 'while tr"   3 minutes ago       Up 3 minutes                            d1

# docker logs -f b89b9ce64d34
hello world
hello world
hello world
hello world
hello world

# docker logs -f -t --tail 2 b89b9ce64d34
2016-06-26T10:13:19.786516589Z hello world
2016-06-26T10:13:20.788871572Z hello world
2016-06-26T10:13:21.791921389Z hello world

# docker top b89b9ce64d34
UID               PID               PPID                C                   STIME               TTY               TIME                CMD
root                4156                4148                0                   06:05               ?                   00:00:00            /bin/sh -c while true;do echo hello world;sleep 1;done;
root                4850                4156                0                   06:16               ?                   00:00:00            sleep 1
</code></pre>
<pre><code>docker logs [-f] [-t] [--tail] 容器名或id                查看容器内WEB应用程序日志
</code></pre>
<p>-f --follow=true|false,默认false,一直跟随log变化<br>
-t --timestamps=true|false,默认false,加上时间戳<br>
--tail="all",返回最新多少条日志</p>
<p>在运行的容器中启动新的进程:</p>
<pre><code class="language-shell">docker exec [-d] [-i] [-t] 容器名
</code></pre>
<p>停止守护式进程:</p>
<pre><code>docker stop 容器名      发送停止信号,等待关闭
docker kill 容器名      直接关闭容器
</code></pre>
<h3 id="在容器中部署静态网站">在容器中部署静态网站</h3>
<pre><code>docker run -d -p 80 -i -t ubuntu /bin/bash   主机端口随机
docker run -d -p 8080:80 -i -t ubuntu /bin/bash主机端口自定义
docker run -d -p 0.0.0.0:80 -i -t ubuntu /bin/bash
docker run -d -p 0.0.0.0:8080:80 -i -t ubuntu /bin/bash
</code></pre>
<p>-P --publish-all=true|false,默认false<br>
-p --publish=[],自定义端口,将容器内部使用的网络端口映射到我们使用的主机上。</p>
<pre><code class="language-shell">docker run -d -P training/webapp python app.py 后台运行一个容器应用
docker run -d -p 5000:5000 training/webapp python app.py 容器内部的 5000 端口映射到我们本地主机的 5000 端口上
</code></pre>
<pre><code>docker port 容器id                        查看到容器的端口映射
</code></pre>
<p>Nginx部署示例:</p>
<pre><code># 创建映射端口为80的交互式界面:
docker run -p 80 --name web -i -t ubuntu /bin/bash

# 第一次使用更新源
apt-get update

# 安装nginx
apt-get install nginx

# 安装vim
apt-get install vim

whereis nginx
nginx: /usr/sbin/nginx /etc/nginx /usr/share/nginx

vim /etc/nginx/conf.d/localhost.conf
</code></pre>
<p>发现配置文件在/etc/nginx/conf.d下面:</p>
<p>conf.d/localhost.conf</p>
<pre><code class="language-shell">server {
    listen       80;
    server_namelocalhost;
   
    location / {
      root   /var/www/;
      indexindex.html index.htm;
    }   
   
}
</code></pre>
<p>新建个目录:</p>
<pre><code>mkdir -p /var/www/

vim /var/www/index.html
</code></pre>
<p>内容随便写。</p>
<pre><code># 启动nginx
nginx
</code></pre>
<p>使用Crtl+P(即Crtl+shift+p)退出容器,并后台运行。<br>
查看:</p>
<pre><code># docker port web
80/tcp -&gt; 0.0.0.0:32769

# docker top web
UID               PID               PPID                C                   STIME               TTY               TIME                CMD
root                12123               12113               0                   07:14               pts/2               00:00:00            /bin/bash
root                12159               12123               0                   07:14               ?                   00:00:00            nginx: master process nginx
33                  12160               12159               0                   07:14               ?                   00:00:00            nginx: worker process

# curl http://127.0.0.1:32769

</code></pre>
<p>正常的话会显示网页内容。</p>
<p>如果exit退出了容器,想开启nginx服务,还可以:</p>
<pre><code>docker start web
docker exec web nginx
</code></pre>
<h3 id="链接另一个容器">链接另一个容器</h3>
<p>我们可以使用<code>--link</code>使用另一个容器的服务。<br>
创建mysql_db 容器:</p>
<pre><code class="language-shell">docker run --name mysql_db -e MYSQL_ROOT_PASSWORD=123456 -d mysql
</code></pre>
<p>创建一个应用,并使用刚才创建的mysql_db容器服务:</p>
<pre><code class="language-shell">docker run --name some-wordpress --link mysql_db:mysql -p 8001:80 -d wordpress
</code></pre>
<h2 id="docker镜像">Docker镜像</h2>
<h3 id="搜索镜像">搜索镜像</h3>
<pre><code class="language-shell">docker search [-s] IMAGE
</code></pre>
<h3 id="下载镜像">下载镜像</h3>
<pre><code class="language-shell">docker pull NAME[:TAG|@DIGEST]

# docker pull ubuntu:16.04
# docker pull daocloud.io/library/ubuntu:16.04
</code></pre>
<p>下载镜像名称其实由三部分组成:daocloud.io/library/ubuntu:16.04<br>
其中其中daocloud.io是注册服务器地址,默认是registry.hub.docker.com;ubuntu是仓库名,16.04是标签名,默认是latest。</p>
<h3 id="查看已下载镜像列表">查看已下载镜像列表</h3>
<pre><code class="language-shell">docker images [-a]

# docker images
REPOSITORY                     TAG               IMAGE ID            CREATED             SIZE
daocloud.io/library/ubuntu       16.04               12543ced0f6f      2 weeks ago         122.4 MB
ubutun                           latest            12543ced0f6f      2 weeks ago         122.4 MB
daocloud.io/daocloud/dao-2048    latest            6c1ff658e77e      3 months ago      7.598 MB
daocloud.io/daocloud/alpine      latest            e9f3e32a4303      3 months ago      11.52 MB
daocloud.io/library/centos       7.1.1503            fac97c5c4748      8 months ago      212.1 MB
daocloud.io/daocloud/dao-redis   master-init         173a30377d85      13 months ago       190.4 MB
</code></pre>
<p>各个选项说明:</p>
<pre><code>REPOSTITORY:表示镜像的仓库源
TAG:镜像的标签
IMAGE ID:镜像ID
CREATED:镜像创建时间
SIZE:镜像大小
</code></pre>
<p>同一仓库源可以有多个 TAG,代表这个仓库源的不同个版本,我们使用 REPOSTITORY:TAG 来定义不同的镜像。</p>
<h3 id="给镜像添加标签">给镜像添加标签</h3>
<pre><code class="language-shell">docker tag IMAGE[:TAG] NAME[:TAG]

# docker tag daocloud.io/library/ubuntu:16.04 ubuntu:latest
</code></pre>
<h3 id="删除镜像">删除镜像</h3>
<pre><code class="language-shell">docker rmi IMAGE

# 按标签删除:多个标签,仅会删除当前标签,不会删除镜像
# docker rmi ubuntu:latest
# 按ID删除:直接删除镜像
# docker rmi 12543ced0f6f
</code></pre>
<p>选项:<br>
<code>-f, --force</code>强制删除镜像<br>
<code>--no-prune</code>   不删除untagged parents</p>
<h3 id="导出镜像">导出镜像</h3>
<pre><code class="language-shell">docker save IMAGE

# docker save -o ubuntu_latest.tar ubuntu:latest
# ls -l
-rw-r--r--. 1 root root 128086528 Jun 28 12:39 ubuntu_latest.tar
</code></pre>
<p>选项:<br>
<code>-o, --output</code> 写入到文件</p>
<h3 id="导入镜像">导入镜像</h3>
<pre><code class="language-shell">docker load --input ubuntu_latest.tar
# 或者
docker load &lt; ubuntu_latest.tar
</code></pre>
<p>选项:<br>
<code>-i, --input</code>从压缩包载入镜像</p>
<h3 id="创建镜像">创建镜像</h3>
<p>当我们从docker镜像仓库中下载的镜像不能满足我们的需求时,我们可以通过以下两种方式对镜像进行更改。<br>
1.从已经创建的容器中更新镜像,并且提交这个镜像<br>
2.使用 Dockerfile 指令来创建一个新的镜像</p>
<p><strong>从容器生成镜像</strong></p>
<p>假设有一容器2c74d574293f,可以使用commit命令生成镜像:</p>
<pre><code class="language-shell">docker commit -m "create images" -a "52fhy"2c74d574293f52fhy/test:v1
</code></pre>
<p>-m 加一些改动信息,-a 指定作者相关信息,2c74d这一串为旧容器id,再后面为新镜像的名字。</p>
<h3 id="上传镜像">上传镜像</h3>
<pre><code class="language-shell">docker push NAME[:TAG|@DIGEST]
</code></pre>
<p>选项:<br>
<code>--disable-content-trust=true</code>   跳过镜像签名</p>
<h2 id="docker仓库">Docker仓库</h2>
<p>仓库是集中存放镜像的地方。官方提供的公共仓库是https://hub.docker.com。不用注册即可使用里面的众多仓库资源,包含了常用的ubuntu、centos、php、nginx、mysql等仓库。</p>
<p>由于国外仓库访问比较慢,可以使用国内的仓库,一般需要注册,使用docker pull的时候需要指明注册服务器地址。</p>
<ul>
<li>DaoCloud https://www.daocloud.io/</li>
<li>阿里云 https://dev.aliyun.com/search.html?spm=5176.775974865.0.0.Iot0iJ</li>
<li>网易蜂巢 https://c.163.com/</li>
</ul>
<p>示例:</p>
<pre><code>docker pull registry.aliyuncs.com/acs-sample/mysql
</code></pre>
<p>其中<code>registry.aliyuncs.com</code>是注册服务器地址,<code>acs-sample/mysql</code>是仓库名,所有者是<code>acs-sample</code>,没有指定镜像标签,则默认是<code>latest</code>。</p>
<p>根据所存储的镜像公开分享与否,Docker仓库可以分为公开仓库(Public)和私有仓库(Private)两种形式。</p>
<h3 id="搭建私有仓库">搭建私有仓库</h3>
<p>详见:Docker私有仓库搭建</p>
<h2 id="docker数据卷及数据卷容器">Docker数据卷及数据卷容器</h2>
<p>在使用容器的过程中,我们可能需要共享数据:<br>
1、共享本地主机数据到容器;<br>
2、共享容器数据到另一个容器。</p>
<p>Docker里的数据卷及数据卷容器恰好满足了这个需求。</p>
<h3 id="数据卷">数据卷</h3>
<p>数据卷(Data Volumes)是一个可供容器使用的特殊目录,它提供了很多有用的特性:</p>
<ul>
<li>对数据卷的修改会立马生效</li>
<li>数据卷会一直存在,直到没有容器使用</li>
<li>数据卷可以被多个容器使用</li>
</ul>
<p>数据卷类似于Linux的mount。实质是在当前机器映射了一个目录到容器内部。</p>
<p>创建或运行容器的时候,使用<code>-v</code>创建一个数据卷,多次使用<code>-v</code>可以创建多个数据卷。</p>
<pre><code class="language-shell">docker run-d -P --name test1 -v /data1ubuntu

# 挂载本地已有目录到容器中
docker run-d -P --name test2 -v /tmp/data2:/data2ubuntu

# 挂载本地已有目录到容器中,指定只读
docker run-d -P --name test3-v /tmp/data3:/data3:ro ubuntu
</code></pre>
<p>挂载的数据卷默认权限是读写<code>rw</code>。</p>
<h3 id="数据卷容器">数据卷容器</h3>
<p>数据卷容器(Data Volume Dontainers)其实就是一个普通的容器,只是我们专门用它提供数据卷供其它容器挂载使用。</p>
<p>创建数据库容器很简单,创建一个普通容器就行了:</p>
<pre><code class="language-shell">docker run --name db1-v /data ubuntu
</code></pre>
<p>其他容器使用该数据卷容器:</p>
<pre><code class="language-shell">docker run-it --name test4--volumes-from db1 ubuntu
</code></pre>
<p>使用<code>--volumes-from</code>指定数据卷容器。多个<code>--volumes-from</code>将挂载多个数据卷容器。</p>
<p>注意:使用<code>--volumes-from</code>参数所挂载的数据卷容器本身并不需要保持运行状态。如果删除了挂载的容器,数据卷并不会被自动删除,如果要删除一个数据卷,必需使用<code>docker rm -v</code>命令来指定同时删除管联的容器。</p>
<h2 id="使用dockerfile创建镜像">使用Dockerfile创建镜像</h2>
<p>Dockerfile用来创建一个自定义的image,包含了用户指定的软件依赖等。Dockerfile文件可以用docker build命令生成一个新的镜像。</p>
<p>Dockerfile文件示例:</p>
<pre><code>FROM daocloud.io/centos:7

# Install Nginx.
# WORKDIR /etc/yum.repos.d/
RUN \
   yum update -y &amp;&amp; \
   yum install -y wget &amp;&amp; \
#   wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo &amp;&amp; \
   wget -O /etc/yum.repos.d/CentOs-Base.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo &amp;&amp; \
   yum makecache &amp;&amp; \
   yum update -y &amp;&amp; \
   yum install -y vim &amp;&amp; \
   yum install -y nginx &amp;&amp; \
   yum install -y net-tools &amp;&amp; \
   echo "daemon off;" &gt;&gt; /etc/nginx/nginx.conf &amp;&amp; \
   echo "master_processoff;" &gt;&gt; /etc/nginx/nginx.conf
   # Define mountable directories.
   VOLUME ["/usr/share/nginx", "/etc/nginx/conf.d", "/var/log/nginx"]
   # Define working directory.
   WORKDIR /etc/nginx
   # Define default command.
   CMD ["/usr/sbin/nginx"]
   # Expose ports.
   EXPOSE 80
   EXPOSE 443
</code></pre>
<p>运行如下命令:</p>
<pre><code>docker build -t nginx:v1 .
</code></pre>
<p>进行镜像构建。成功后,从生成的镜像运行容器:</p>
<pre><code>docker run -d -p 8090:80 nginx:v1
</code></pre>
<h3 id="dockerfile文件语法">Dockerfile文件语法</h3>
<p><strong>(1)FROM(指定基础image)</strong><br>
构建指令,必须指定且需要在Dockerfile其他指令的前面。后续的指令都依赖于该指令指定的image。FROM指令指定的基础image可以是官方远程仓库中的,也可以位于本地仓库。镜像可以指定标签。格式:</p>
<pre><code>FROM &lt;image&gt;:&lt;tag&gt;
</code></pre>
<p><strong>(2)MAINTAINER(用来指定镜像创建者信息)</strong><br>
构建指令,用于将image的制作者相关的信息写入到image中。当我们对该image执行docker inspect命令时,输出中有相应的字段记录该信息。<br>
格式:</p>
<pre><code>MAINTAINER &lt;name&gt;
</code></pre>
<p><strong>(3)RUN</strong><br>
构建指令,RUN可以运行任何被基础image支持的命令。如基础image选择了ubuntu,那么软件管理部分只能使用ubuntu的命令。RUN指令可以有多条,每条RUN指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时,可以用\来换行。<br>
该指令有两种格式:</p>
<pre><code># 在shell终端中运行 - `/bin/sh -c`
RUN &lt;command&gt;

# 使用exec执行
RUN ["executable", "param1", "param2" ... ]
</code></pre>
<p><strong>(4)CMD(设置容器启动时执行的操作)</strong><br>
设置指令,用于容器启动时指定的操作。该操作可以是执行自定义脚本,也可以是执行系统命令。该指令只能在文件中存在一次,如果有多个,则只执行最后一条。<br>
该指令有三种格式:</p>
<pre><code># 格式一:like an exec, this is the preferred form
CMD ["executable","param1","param2"]

# 格式二:as a shell
CMD command param1 param2

# 当Dockerfile指定了ENTRYPOINT,那么使用下面的格式:作为ENTRYPOINT的缺省参数
CMD ["param1","param2"]
</code></pre>
<p>注意:</p>
<ol>
<li>CMD运行在镜像构建之后,容器启动的时候;</li>
<li>CMD只执行最后一条</li>
<li>CMD可以被用户指定的命令覆盖</li>
</ol>
<p><strong>(5)ENTRYPOINT(设置容器启动时执行的操作)</strong><br>
设置指令,指定容器启动时执行的命令,可以多次设置,但是只有最后一个有效。<br>
两种格式:</p>
<pre><code># 格式一:like an exec, this is the preferred form
ENTRYPOINT ["executable", "param1", "param2"]

# 格式二:as a shell
ENTRYPOINT command param1 param2
</code></pre>
<p>该指令的使用分为两种情况,一种是独自使用,另一种和CMD指令配合使用。</p>
<p>当独自使用时,如果你还使用了CMD命令且CMD是一个完整的可执行的命令,那么CMD指令和ENTRYPOINT会互相覆盖只有最后一个CMD或者ENTRYPOINT有效:</p>
<pre><code># CMD指令将不会被执行,只有ENTRYPOINT指令被执行
CMD echo “Hello, World!”
ENTRYPOINT ls -l
</code></pre>
<p>另一种用法和CMD指令配合使用来指定ENTRYPOINT的默认参数,这时CMD指令不是一个完整的可执行命令,仅仅是参数部分;ENTRYPOINT指令只能使用JSON方式指定执行命令,而不能指定参数:</p>
<pre><code>FROM ubuntu
CMD ["-l"]
ENTRYPOINT ["/usr/bin/ls"]
</code></pre>
<p>注意:</p>
<ol>
<li>和CMD指令基本一样,但是不能被用户指定的命令所覆盖;</li>
<li>可以和CMD组合使用,ENTRYPOINT提供不可变得命令,CMD提供缺省参数。</li>
</ol>
<p><strong>(6)USER(设置容器的用户)</strong><br>
设置指令,设置启动容器的用户,默认是root用户。</p>
<pre><code># 指定memcached的运行用户
ENTRYPOINT ["memcached"]
USER daemon

# 或
ENTRYPOINT ["memcached", "-u", "daemon"]
</code></pre>
<p><strong>(7)EXPOSE(指定容器需要映射到宿主机器的端口)</strong><br>
设置指令,该指令会将容器中的端口映射成宿主机器中的某个端口。格式为:</p>
<pre><code>EXPOSE &lt;port&gt; [&lt;port&gt; ...]
</code></pre>
<p>例如:</p>
<pre><code>EXPOSE 80 443 11211
</code></pre>
<p>告诉Docker服务端容器暴露的端口号,供互联系统使用。在启动容器时需要通过-P,Docker主机会自动分配一个端口转发到指定的端口;使用-p,则可以具体指定哪个本地端口映射过来。</p>
<p><strong>(8)ENV(用于设置环境变量)</strong><br>
构建指令,在image中设置一个环境变量。格式:</p>
<pre><code>ENV &lt;key&gt; &lt;value&gt;
</code></pre>
<p>设置了后,后续的RUN命令都可以使用,容器启动后,可以通过<code>docker inspect</code>查看这个环境变量,也可以通过在<code>docker run --env key=value</code>时设置或修改环境变量。</p>
<p>假如你安装了JAVA程序,需要设置<code>JAVA_HOME</code>,那么可以在Dockerfile中这样写:</p>
<pre><code>ENV JAVA_HOME /path/to/java/dirent
</code></pre>
<p><strong>(9)ADD(从src复制文件到容器的dest路径)</strong><br>
构建指令,所有拷贝到容器中的文件和文件夹权限为0755,uid和gid为0。格式为:</p>
<pre><code>ADD &lt;src&gt; &lt;dest&gt;
</code></pre>
<p><code>&lt;src&gt;</code> 是相对被构建的源目录的相对路径,可以是文件或目录的路径,也可以是一个远程的文件url;<code>&lt;dest&gt; </code>是容器中的绝对路径。</p>
<p>该命令将复制指定的<code>&lt;src&gt;</code>到容器中的<code>&lt;dest&gt;</code>。其中<code>&lt;src&gt;</code>可以是Dockerfile所在目录的一个相对路径(文件或目录);也可以是一个URL;还可以是一个tar文件(自动解压为目录)。</p>
<p>如果是一个目录,那么会将该目录下的所有文件添加到容器中,不包括目录;如果文件是可识别的压缩格式,则docker会帮忙解压缩(注意压缩格式);如果<code>&lt;src&gt;</code>是文件且<code>&lt;dest&gt;</code>中不使用斜杠结束,则会将<code>&lt;dest&gt;</code>视为文件,<code>&lt;src&gt;</code>的内容会写入<code>&lt;dest&gt;</code>;如果<code>&lt;src&gt;</code>是文件且<code>&lt;dest&gt;</code>中使用斜杠结束,则会<code>&lt;src&gt;</code>文件拷贝到<code>&lt;dest&gt;</code>目录下。</p>
<p><strong>(10)COPY</strong><br>
格式为</p>
<pre><code>COPY &lt;src&gt; &lt;dest&gt;
</code></pre>
<p>复制本地主机的<code>&lt;src&gt;</code>(为Dockerfile所在目录的相对路径,文件或目录)为容器中的<code>&lt;dest&gt;</code>。目标路径不存在时,会自动创建。<br>
当使用本地目录为源目录时,推荐使用COPY。</p>
<p><strong>(11)VOLUME(指定挂载点))</strong><br>
设置指令,使容器中的一个目录具有持久化存储数据的功能,该目录可以被容器本身使用,也可以共享给其他容器使用。我们知道容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。当容器中的应用有持久化数据的需求时可以在Dockerfile中使用该指令。格式:</p>
<pre><code>VOLUME ["&lt;mountpoint&gt;"]
</code></pre>
<p>示例:</p>
<pre><code>FROM base
VOLUME ["/tmp/data"]
</code></pre>
<p>运行通过该Dockerfile生成image的容器,<code>/tmp/data</code>目录中的数据在容器关闭后,里面的数据还存在。例如另一个容器也有持久化数据的需求,且想使用上面容器共享的<code>/tmp/data</code>目录,那么可以运行下面的命令启动一个容器:</p>
<pre><code>docker run -t -i -rm -volumes-from container1 image2 bash
</code></pre>
<p>container1为第一个容器的ID,image2为第二个容器运行image的名字。</p>
<p><strong>(12)WORKDIR(切换目录)</strong><br>
设置指令,可以多次切换(相当于cd命令),对RUN,CMD,ENTRYPOINT生效。格式:</p>
<pre><code>WORKDIR /path/to/workdir
</code></pre>
<p>示例:</p>
<pre><code># 在 /p1/p2 下执行 vim a.txt
WORKDIR /p1
WORKDIR p2
RUN vim a.txt
</code></pre>
<p><strong>(13)ONBUILD(在子镜像中执行)</strong></p>
<pre><code>ONBUILD &lt;Dockerfile关键字&gt;
</code></pre>
<p>ONBUILD 指定的命令在构建镜像时并不执行,而是在它的子镜像中执行。</p>
<p><strong>(14)ARG(指定构建过程中使用的环境变量)</strong></p>
<pre><code>ARG buildno
ARG password

RUN echo "Build number: $buildno"
RUN script-requiring-password.sh "$password"
</code></pre>
<h2 id="docker-compose">Docker Compose</h2>
<p>Compose是用于定义和运行复杂Docker应用的编排工具(旧版本叫Fig)。你可以在一个文件中定义一个多容器的应用,然后使用一条命令来启动你的应用,然后所有相关的操作都会被自动完成。</p>
<p>资料:<br>
https://docs.docker.com/compose<br>
https://github.com/docker/compose</p>
<h3 id="安装compose">安装Compose</h3>
<pre><code class="language-shell"># 方法一:
curl -L https://github.com/docker/compose/releases/download/1.8.0/docker-compose-`uname -s`-`uname -m` &gt; /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

# 方法二:
yum install python-pip python-dev
pip install docker-compose
</code></pre>
<p>查看版本号:</p>
<pre><code>$ docker-compose--version
docker-compose 1.8.0
</code></pre>
<h3 id="compose示例">Compose示例</h3>
<p>docker-compose.yml内容</p>
<pre><code class="language-shell">web:
image: wordpress:latest
links:
    - db:mysql
ports:
    - "8002:80"
db:
image: mysql
environment:
    - MYSQL_ROOT_PASSWORD=123456
</code></pre>
<p>启动应用:</p>
<pre><code>docker-compose up
</code></pre>
<h3 id="docker-composeyml常用指令">docker-compose.yml常用指令</h3>
<p>image:镜像的ID<br>
build:直接从pwd的Dockerfile来build,而非通过image选项来pull<br>
links:连接到那些容器。每个占一行,格式为SERVICE[:ALIAS],例如 – db[:database]<br>
external_links:连接到该compose.yaml文件之外的容器中,比如是提供共享或者通用服务的容器服务。格式同links<br>
command:替换默认的command命令<br>
ports: 导出端口。格式可以是:</p>
<pre><code>ports:
    -"3000"
    -"8000:8000"
    -"127.0.0.1:8001:8001"
</code></pre>
<p>expose:导出端口,但不映射到宿主机的端口上。它仅对links的容器开放。格式直接指定端口号即可。<br>
volumes:加载路径作为卷,可以指定只读模式:</p>
<pre><code>volumes:
    -/var/lib/mysql
    - cache/:/tmp/cache
    -~/configs:/etc/configs/:ro
</code></pre>
<p>volumes_from:加载其他容器或者服务的所有卷</p>
<pre><code>environment:
    - RACK_ENV=development
    - SESSION_SECRET
</code></pre>
<p>env_file:从一个文件中导入环境变量,文件的格式为RACK_ENV=development<br>
extends:扩展另一个服务,可以覆盖其中的一些选项。一个sample如下:</p>
<pre><code># common.yml
webapp:
build:./webapp
environment:
    - DEBUG=false
    - SEND_EMAILS=false

# development.yml
web:extends:
    file: common.yml
    service: webapp
ports:
    -"8000:8000"
links:
    - db
environment:
    - DEBUG=true
db:
image: postgres
</code></pre>
<p>net:容器的网络模式,可以为"bridge", "none", "container:", "host"中的一个。<br>
dns:可以设置一个或多个自定义的DNS地址。<br>
dns_search:可以设置一个或多个DNS的扫描域。<br>
其他的working_dir, entrypoint, user, hostname, domainname, mem_limit, privileged, restart, stdin_open, tty, cpu_shares,和docker run命令是一样的,这些命令都是单行的命令。例如:</p>
<pre><code>cpu_shares:73
working_dir:/code
entrypoint: /code/entrypoint.sh
user: postgresql
hostname: foo
domainname: foo.com
mem_limit:1000000000
privileged:true
restart: always
stdin_open:true
tty:true
</code></pre>
<h3 id="docker-compose-自定义网络">docker-compose 自定义网络</h3>
<p>创建自定义网络时,指定了网段</p>
<pre><code class="language-bash">$ docker network create --subnet=172.18.0.0/16 mynetwork
</code></pre>
<p>在 yml 文件中,指定一下外部自定义网络,并绑定 IP 即可。<br>
示例</p>
<pre><code class="language-yml">version: '3'
services:
mysql:
    image: mysql:5.7
    container_name: mysql
    ports:
      - '3336:3306'
    volumes:
      - /data/mysql/conf:/etc/mysql/conf.d
      - /data/mysql/data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=123456
    networks:
      default:
      ipv4_address: 172.18.0.31

networks:
default:
    external:
      name: mynetwork
</code></pre>
<h2 id="常见问题">常见问题</h2>
<h3 id="安装出错">安装出错</h3>
<p>1、Transaction check error</p>
<pre><code>Transaction check error:
file /usr/lib/systemd/system/blk-availability.service from install of device-mapper-7:1.02.107-5.el7_2.1.x86_64 conflicts with file from package lvm2-7:2.02.105-14.el7.x86_64
file /usr/sbin/blkdeactivate from install of device-mapper-7:1.02.107-5.el7_2.1.x86_64 conflicts with file from package lvm2-7:2.02.105-14.el7.x86_64
file /usr/share/man/man8/blkdeactivate.8.gz from install of device-mapper-7:1.02.107-5.el7_2.1.x86_64 conflicts with file from package lvm2-7:2.02.105-14.el7.x86_64

Error Summary
</code></pre>
<p>运行命令:<code>yum install libdevmapper* -y</code></p>
<p>2、http://blog.csdn.net/baidu_36342103/article/details/69357438</p>


</div>
<div id="MySignature" role="contentinfo">
    (本文完)
<br><br>


欢迎关注公众号"飞鸿影记(fhyblog)",探寻物件背后的逻辑,记录生活真实的影子。
<div style="text-align: center"><span style="color: #808000"><img src="https://images2015.cnblogs.com/blog/663847/201703/663847-20170331215930477-1406562582.jpg" alt="" width="250" height="250"></span></div>


<div>
<p><strong>作者:飞鸿影</strong></p>
<p><strong>出处:http://52fhy.cnblogs.com/</strong></p>
</div>

<hr>

<p style="border: silver 1px dashed; padding: 8px 5px; font-weight: bold">版权申明:没有标明转载或特殊申明均为作者原创。本文采用以下协议进行授权,自由转载 - 非商用 - 非衍生 - 保持署名 | Creative Commons BY-NC-ND 3.0,转载请注明作者及出处。</p>

<hr>


<div style="text-align: center;display:none"><span style="color: #808000"><img src="https://images2018.cnblogs.com/blog/663847/201805/663847-20180515232241445-706573186.png" alt="" width="250" height="250"></span></div><br><br>
来源:https://www.cnblogs.com/52fhy/p/5638571.html
頁: [1]
查看完整版本: Docker学习笔记