• 欢迎访问蜷缩的蜗牛博客 蜷缩的蜗牛
  • 微信搜索: 蜷缩的蜗牛 | 联系站长 kbsonlong@qq.com
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

Docker

Linux 蜷缩的蜗牛 2年前 (2017-03-14) 43次浏览 已收录 0个评论

一、基本概念

1、镜像(Image)

    Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

 

2、容器(Container)

    镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

    容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。

 

3、仓库(Registry)

    镜像构建完成后,可以很容易的在当前宿主上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。

 

 

二、Docker 安装  (官方地址:https://docs.docker.com/engine/installation/)

Docker 官网提供一键安装脚本

curl -sSL https://get.docker.com/ | sh

阿里云安装脚本

curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh -

 

DaoCloud 的安装脚本

curl -sSL https://get.daocloud.io/docker | sh

 

yum 安装

配置 yum 源

tee /etc/yum.repos.d/docker.repo <<-'EOF'
[dockerrepo]
name=Docker Repository
baseurl=https://yum.dockerproject.org/repo/main/centos/6/
enabled=1
gpgcheck=1
gpgkey=https://yum.dockerproject.org/gpg
EOF
 yum install docker-engine

 

启动 Docker 引擎

service docker start

 

三、配置加速器

由于某些原因国内访问 Docker 官方仓库(Registry)较慢,国内一些云服务厂商提供加速器供国内用户下载镜像,如阿里云加速器DaoCloud 加速器灵雀云加速器

修改/etc/sysconfig/docker 的 other_args 选项,配置加速器地址,阿里云提供专属加速器地址

cat /etc/sysconfig/docker |grep -v '#'


other_args="--registry-mirror=https://so9gt83b.mirror.aliyuncs.com"

重启并查看加速器是否生效

# /etc/init.d/docker restart
Stopping docker:                                           [  OK  ]
Starting docker:                                       [  OK  ]

# ps -ef  |grep dock
root      1811     1  0 09:41 pts/0    00:00:40 /usr/bin/docker -d --registry-mirror=https://so9gt83b.mirror.aliyuncs.com
root      4819  1660  0 11:16 pts/0    00:00:00 grep dock

 

四、Docker 一些常用命令

docker pull <image name>   ##下载镜像

docker images  ##查看本地镜像

docker rmi <IMAGE ID> ##删除镜像,image id 通过 docker images 获取

docker search <image name> ##查找仓库中镜像

docker run <image name> ##docker 先检查本地是否存在 image,如果存在直接启动容器,不存在将到仓库下载并启动容器
docker run –name webserver -d -p 81:80 nginx  ##用 nginx 镜像启动一个容器,命名为 webserver,并且映射了 81 端口,这样我们可以用浏览器去访问这个 nginx 服务器。

docker exec -it webserver bash  ##进入交互式命令行

docker commit -a “kbsonlong <kbsonlong@along.party>” -m “修改首页” webserver nginx:v2    ##提交修改定制后的镜像

docker history nginx:v2  ##查看历史提交记录

image

docker ps –a  ## 查看容器(CONTAINER )

# docker ps -a
 CONTAINER ID        IMAGE                                                              COMMAND                CREATED             STATUS                         PORTS                         NAMES
 b5520d9d8834        mynginx:last                                                       "nginx -g 'daemon of   10 seconds ago      Up 10 seconds                  443/tcp, 0.0.0.0:81->80/tcp   myweb3                     
1b4ea4be7cc9        mynginx:last                                                       "nginx -g 'daemon of   47 seconds ago      Exited (0) 29 seconds ago                                    myweb2                     
d14e92f0b34d        myip                                                               "curl -s http://ip.c   9 minutes ago       Exited (0) 9 minutes ago                                     suspicious_goldstine       
c251896d0a7e        d4350798c2ee9f080caff7559bf4d5a48a1862330e145fe7118ac721da74a445   "/bin/sh -c 'yum upd   11 minutes ago      Exited (1) 10 minutes ago                                    determined_lumiere         
9b0ae4d5c520        d4350798c2ee9f080caff7559bf4d5a48a1862330e145fe7118ac721da74a445   "/bin/sh -c 'yum upd   13 minutes ago      Exited (1) 12 minutes ago                                    nostalgic_cori             
acf92072616a        d4350798c2ee9f080caff7559bf4d5a48a1862330e145fe7118ac721da74a445   "/bin/sh -c 'apt-get   15 minutes ago      Exited (127) 15 minutes ago                                  tender_ritchie             
a6715fd9e01b        mynginx:v1                                                         "nginx -g 'daemon of   About an hour ago   Exited (0) About an hour ago                                 myweb                      
58e07b94453e        nginx:v2                                                           "nginx -g 'daemon of   3 hours ago                                                                      web2                       
0a76135898a8        nginx                                                              "nginx -g 'daemon of   3 hours ago         Exited (0) 2 hours ago                                       webserver                  
fef8611d303b        wordpress                                                          "docker-entrypoint.s   3 hours ago         Exited (130) 3 hours ago                                     cranky_pike                
7fe7b0281521        wordpress                                                          "docker-entrypoint.s   3 hours ago         Exited (2) 3 hours ago                                       angry_fermi                
f0d5ada0177c        busybox                                                            "/bin/echo hello kbs   19 hours ago        Exited (0) 19 hours ago                                      condescending_archimedes   
9e1656d6ebbd        busybox                                                            "/bin/echo hello"      19 hours ago        Exited (0) 19 hours ago                                      focused_archimedes

 

docker help <command>  ##命令用法帮助

 

五、使用 Dockerfile 定制镜像

Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

例如:定制一个 nginx 镜像

mkdir mynginx
cd mynginx
cat Dockerfile
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

这个 Dockerfile 涉及两个指令:FROM 和 RUN

FROM:指定基础镜像 nginx

RUN : 执行命令

从上面代码可以看到 RUN 指令就像直接执行 shell 命令,那么我们可以像写 shell 脚本一样每个 RUN 指定对应一条命令行吗?

FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
RUN echo '<h2>Hello, Docker!</h2>' > /usr/share/nginx/html/index.html
RUN echo '<h3>Hello, Docker!</h3>' > /usr/share/nginx/html/index.html

上文说到了每一条指令构建一层 ,所以上面的写法实际上创建了 3 层镜像,而Union FS 是有最大层数限制的,比如 AUFS,曾经是最大不得超过 42 层,现在是不得超过 127 层结果就是产生非常臃肿、非常多层的镜像,不仅仅增加了构建部署的时间,也很容易出错。所以在构建时,尽可能的将实现一个目的的操作组合起来,尽可能的使用一层完成。

 

构建镜像

docker build –t <images name>:<tag> <上下文路径/URL/->

# docker build -t mynginx:last .
Sending build context to Docker daemon 3.584 kB
Sending build context to Docker daemon 
Step 0 : FROM nginx
 ---> 00bba88663ff
Step 1 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
 ---> Running in 4e357dc015ea
 ---> e72d8cf6173d
Removing intermediate container 4e357dc015ea
Successfully built e72d8cf6173d
docker images mynginx
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
mynginx             last                e72d8cf6173d        8 seconds ago       181.8 MB

可以看到构建了一个 mynginx:last 的镜像;现在用 mynginx:last 镜像启动一个容器

# docker run --name myweb -d -p 81:80 mynginx:last
a6715fd9e01bfa6f7a013aa06558df5de676874b1ea6a5f1b25f6f41b3368816
# netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name   
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      1333/sshd           
tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN      1437/master         
tcp        0      0 :::81                       :::*                        LISTEN      5209/docker-proxy   
tcp        0      0 :::22                       :::*                        LISTEN      1333/sshd           
tcp        0      0 ::1:25                      :::*                        LISTEN      1437/master         
# curl localhost:81
<h1>Hello, Docker!</h1>

 

镜像构建上下文(Context)

如果注意,会看到 docker build 命令最后有一个 . 。. 表示当前目录,而 Dockerfile 就在当前目录,因此不少初学者以为这个路径是在指定 Dockerfile 所在路径,这么理解其实是不准确的。如果对应上面的命令格式,你可能会发现,这是在指定上下文路径。那么什么是上下文呢?

首先我们要理解 docker build 的工作原理。Docker 在运行时分为 Docker 引擎(也就是服务端守护进程)和客户端工具。Docker 的引擎提供了一组 REST API,被称为 Docker Remote API,而如 docker 命令这样的客户端工具,则是通过这组 API 与 Docker 引擎交互,从而完成各种功能。因此,虽然表面上我们好像是在本机执行各种 docker 功能,但实际上,一切都是使用的远程调用形式在服务端(Docker 引擎)完成。也因为这种 C/S 设计,让我们操作远程服务器的 Docker 引擎变得轻而易举。

当我们进行镜像构建的时候,并非所有定制都会通过 RUN 指令完成,经常会需要将一些本地文件复制进镜像,比如通过 COPY 指令、ADD 指令等。而 docker build 命令构建镜像,其实并非在本地构建,而是在服务端,也就是 Docker 引擎中构建的。那么在这种客户端/服务端的架构中,如何才能让服务端获得本地文件呢?

这就引入了上下文的概念。当构建的时候,用户会指定构建镜像上下文的路径,docker build 命令得知这个路径后,会将路径下的所有内容打包,然后上传给 Docker 引擎。这样 Docker 引擎收到这个上下文包后,展开就会获得构建镜像所需的一切文件。

如果在 Dockerfile 中这么写:

COPY ./package.json /app/

这并不是要复制执行 docker build 命令所在的目录下的 package.json,也不是复制 Dockerfile 所在目录下的 package.json,而是复制 上下文(context) 目录下的 package.json。

因此,COPY 这类指令中的源文件的路径都是相对路径。这也是初学者经常会问的为什么 COPY ../package.json /app 或者 COPY /opt/xxxx /app 无法工作的原因,因为这些路径已经超出了上下文的范围,Docker 引擎无法获得这些位置的文件。如果真的需要那些文件,应该将它们复制到上下文目录中去。

现在就可以理解刚才的命令 docker build -t nginx:v3 . 中的这个 .,实际上是在指定上下文的目录,docker build 命令会将该目录下的内容打包交给 Docker 引擎以帮助构建镜像。

如果观察 docker build 输出,我们其实已经看到了这个发送上下文的过程:

$ docker build -t nginx:v3 .
Sending build context to Docker daemon 2.048 kB
...

理解构建上下文对于镜像构建是很重要的,避免犯一些不应该的错误。比如有些初学者在发现 COPY /opt/xxxx /app 不工作后,于是干脆将 Dockerfile 放到了硬盘根目录去构建,结果发现 docker build 执行后,在发送一个几十 GB 的东西,极为缓慢而且很容易构建失败。那是因为这种做法是在让 docker build 打包整个硬盘,这显然是使用错误。

一般来说,应该会将 Dockerfile 置于一个空目录下,或者项目根目录下。如果该目录下没有所需文件,那么应该把所需文件复制一份过来。如果目录下有些东西确实不希望构建时传给 Docker 引擎,那么可以用.gitignore 一样的语法写一个 .dockerignore,该文件是用于剔除不需要作为上下文传递给 Docker 引擎的。

那么为什么会有人误以为 . 是指定 Dockerfile 所在目录呢?这是因为在默认情况下,如果不额外指定 Dockerfile 的话,会将上下文目录下的名为 Dockerfile 的文件作为 Dockerfile。

 

Dockerfile 指令

1、FROM 指定基础镜像
     Docker 还存在一个特殊的镜像,名为 scratch

2、RUN 执行命令
     shell 格式:RUN <命令>,就像直接在命令行中输入的命令一样
         RUN echo ‘<h1>Hello, Docker!</h1>’ > /usr/share/nginx/html/index.html
     exec 格式:RUN [“可执行文件”, “参数 1”, “参数 2”],这更像是函数调用中的格式

3、COPY 复制文件

4、ADD 更高级的复制文件

5、CMD 容器启动命令

6、ENT RYPOINT 入口点

7、ENV 设置环境变量
     ENV <key> <value>
    

ENV NODE_VERSION 7.2.0

RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
  && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \
  && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
  && grep " node-v$NODE_VERSION-linux-x64.tar.xz\$" SHASUMS256.txt | sha256sum -c - \
  && tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1 \
  && rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \
  && ln -s /usr/local/bin/node /usr/local/bin/nodejs

     ENV <key1>=<value1> <key2>=<value2>…

ENV VERSION=1.0 DEBUG=on \
    NAME="Happy Feet"

8、ARG 构建参数

9、VOLUME 定义匿名卷

容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中。为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。

 

10、EXPOSE 暴露端口

格式为 EXPOSE <端口 1> [<端口 2>...]

EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P时,会自动随机映射 EXPOSE 的端口。

要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来。-p,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。

 

11、WORKDIR 工作目录

12、USER 指定当前用户

13、HEALTHCHECK 健康检查 (自 1.12 版本 之后,Docker 提供了 HEALTHCHECK 指令)

HEALTHCHECK 支持下列选项:

  • --interval=<间隔>:两次健康检查的间隔,默认为 30 秒;
  • --timeout=<时长>:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;
  • --retries=<次数>:当连续失败指定次数后,则将容器状态视为 unhealthy,默认 3 次。

CMD, ENTRYPOINT 一样,HEALTHCHECK 只可以出现一次,如果写了多个,只有最后一个生效

假设我们有个镜像是个最简单的 Web 服务,我们希望增加健康检查来判断其 Web 服务是否在正常工作,我们可以用 curl 来帮助判断,其 DockerfileHEALTHCHECK 可以这么写

FROM nginx
RUN yum install -y curl 
HEALTHCHECK --interval=5s --timeout=3s \
  CMD curl -fs http://localhost/ || exit 1

 

 

14、ONBUILD


蜷缩的蜗牛 , 版权所有丨如未注明 , 均为原创丨 转载请注明Docker
喜欢 (1)
[]
分享 (0)

您必须 登录 才能发表评论!