Ubuntu 17.04 x64 安装 Docker CE 初窥 Dockerfile 部署 Nginx

Docker 是个划时代的开源项目,它完全释放了计算虚拟化的威力,极大提升了应用的运行效率,下降了云计算资源供应的成本!使用 Docker,可让应用的部署、测试和分发都变得史无前例的高效和轻松!php

不管是应用开发者、运维人员、仍是其余信息技术从业人员,都有必要认识和掌握 Docker,节约有限的时间。html

系统要求

要安装Docker CE,您须要这些Ubuntu版本的64位版本:node

  • Artful 17.10(Docker CE 17.11 Edge及更高版本)
  • ZESTY 17.04
  • Xenial 16.04(LTS)
  • Trusty 14.04(LTS)

Ubuntu x86_64,Linux armhf,s390x(IBM Z)和ppc64le(IBM Power)架构上支持Docker CEpython

卸载旧版本

老版本的Docker被称为dockerdocker-engine。若是安装了这些,请将其卸载:mysql

$ apt-get remove docker docker-engine docker.io

使用存储库进行安装

首次在新的主机上安装Docker CE以前,须要设置Docker存储库。以后,您能够从存储库安装和更新Dockerlinux

  • 设置存储库

1.更新apt软件包索引:nginx

$ apt-get update

2.安装软件包以容许apt经过HTTPS使用存储库:git

$ apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common

3.添加Docker的官方GPG密钥:github

鉴于国内网络问题,强烈建议使用国内源,官方源请在注释中查看。golang

$ curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -

# 官方源
# $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

4.添加 Docker 软件源

鉴于国内网络问题,强烈建议使用国内源,官方源请在注释中查看。

而后,咱们须要向 source.list 中添加 Docker 软件源

$ sudo add-apt-repository \
    "deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu \
    $(lsb_release -cs) \
    stable"
    

# 官方源
# $ sudo add-apt-repository \
#    "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
#    $(lsb_release -cs) \
#    stable"

以上命令会添加稳定版本的 Docker CE APT 镜像源,若是须要最新或者测试版本的 Docker CE 请将 stable 改成 edge 或者 test。从 Docker 17.06 开始,edge test 版本的 APT 镜像源也会包含稳定版本的 Docker

安装Docker CE

1.更新apt软件包索引。

$ apt-get update

2.安装最新版本的Docker CE,或者转到下一步安装特定版本。任何现有的Docker安装都将被替换。

$ apt-get install docker-ce

3.在生产系统上,您应该安装特定版本的Docker CE,而不是始终使用最新版本。此输出被截断。列出可用的版本。

$ apt-cache madison docker-ce

docker-ce | 17.12.0~ce-0~ubuntu | https://download.docker.com/linux/ubuntu zesty/stable amd64 Packages
docker-ce | 17.09.1~ce-0~ubuntu | https://download.docker.com/linux/ubuntu zesty/stable amd64 Packages
docker-ce | 17.09.0~ce-0~ubuntu | https://download.docker.com/linux/ubuntu zesty/stable amd64 Packages
docker-ce | 17.06.2~ce-0~ubuntu | https://download.docker.com/linux/ubuntu zesty/stable amd64 Packages
docker-ce | 17.06.1~ce-0~ubuntu | https://download.docker.com/linux/ubuntu zesty/stable amd64 Packages
docker-ce | 17.06.0~ce-0~ubuntu | https://download.docker.com/linux/ubuntu zesty/stable amd64 Packages

列表的内容取决于启用了哪一个存储库。选择一个特定的版本进行安装。第二列是版本字符串。第三列是存储库名称,它指出了软件包来自哪一个存储库,并经过扩展其稳定性级别。要安装特定版本,请将版本字符串附加到包名称,并用等号(=)将它们分开:

$ sudo apt-get install docker-ce=<VERSION>

4.经过运行hello-world 映像验证是否正确安装了Docker CE

$ docker run hello-world

这个命令下载一个测试图像并在容器中运行。容器运行时,会打印一条信息消息并退出。

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
ca4f61b1923c: Pull complete 
Digest: sha256:445b2fe9afea8b4aa0b2f27fe49dd6ad130dfe7a8fd0832be5de99625dad47cd
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://cloud.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/engine/userguide/

以非root用户身份管理Docker

默认状况下,docker 命令会使用 Unix socketDocker 引擎通信。而只有 root 用户和 docker 组的用户才能够访问 Docker 引擎的 Unix socket。出于安全考虑,通常 Linux 系统上不会直接使用 root 用户。所以,更好地作法是将须要使用 docker 的用户加入 docker 用户组。

要建立docker组并添加您的用户:

1.建立docker组。

$ sudo groupadd docker

2.将您的用户添加到docker组中。

$ sudo usermod -aG docker $USER

3.注销并从新登陆,若是在虚拟机上进行测试,则可能须要从新启动虚拟机才能使更改生效。

4.验证您能够不运行docker命令sudo

$ docker run hello-world

卸载Docker CE

1.卸载Docker CE软件包:

$ sudo apt-get purge docker-ce

2.主机上的图像,容器,卷或自定义配置文件不会自动删除。删除全部图像,容器和卷:

$ sudo rm -rf /var/lib/docker

利用 commit 理解镜像构成

这条命令会用nginx 镜像启动一个容器,命名为 myweb,而且映射了 80 端口,这样咱们能够用浏览器去访问这个 nginx 服务器。

$ docker run --name myweb -d -p 80:80 nginx

直接访问:http://localhost;若是使用的是 Docker Toolbox,或者是在虚拟机、云服务器上安装的 Docker,则须要将 localhost 换为虚拟机地址或者实际云服务器地址。

 Welcome to nginx!

如今,假设咱们很是不喜欢这个欢迎页面,咱们但愿改为欢迎 Docker 的文字,咱们可使用 docker exec 命令进入容器,修改其内容。

$ docker exec -it myweb bash
root@5ceb0c8274ca:/# echo '<h1>Welcome to Docker!</h1>' > /usr/share/nginx/html/index.html
root@5ceb0c8274ca:/# exit
exit

直接访问:http://localhost

 Welcome to Docker!

咱们修改了容器的文件,也就是改动了容器的存储层。咱们能够经过 docker diff 命令看到具体的改动。COMMENT列有备注!

$  docker diff myweb
C /root
A /root/.bash_history
C /run
A /run/nginx.pid
C /usr/share/nginx/html/index.html
C /var/cache/nginx
D /var/cache/nginx/client_temp
D /var/cache/nginx/fastcgi_temp
D /var/cache/nginx/proxy_temp
D /var/cache/nginx/scgi_temp
D /var/cache/nginx/uwsgi_temp
root@souyunku:~/mydocker#

咱们能够用下面的命令将容器保存为镜像:

$ docker commit \
    --author "penglei <admin@souyunku.com>" \
    --message "修改了默认网页" \
    myweb \
    nginx:v2
    
sha256:33b2e2aefccbaba54021c85ef7966c7d488abaa0677728e1b057c56a7734a4f0

其中 --author 是指定修改的做者,而 --message 则是记录本次修改的内容。这点和 git 版本控制类似,不过这里这些信息能够省略留空。

咱们能够在 docker image ls 中看到这个新定制的镜像:

$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
nginx               v2                  33b2e2aefccb        About a minute ago   108MB
nginx               latest              3f8a4339aadd        3 days ago           108MB
hello-world         latest              f2a91732366c        5 weeks ago          1.85kB
$ docker history nginx:v2
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
33b2e2aefccb        2 minutes ago       nginx -g daemon off;                            325B                修改了默认网页
3f8a4339aadd        3 days ago          /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon…   0B                  
<missing>           3 days ago          /bin/sh -c #(nop)  STOPSIGNAL [SIGTERM]         0B                  
<missing>           3 days ago          /bin/sh -c #(nop)  EXPOSE 80/tcp                0B                  
<missing>           3 days ago          /bin/sh -c ln -sf /dev/stdout /var/log/nginx…   22B                 
<missing>           3 days ago          /bin/sh -c set -x  && apt-get update  && apt…   53.2MB              
<missing>           3 days ago          /bin/sh -c #(nop)  ENV NJS_VERSION=1.13.8.0.…   0B                  
<missing>           3 days ago          /bin/sh -c #(nop)  ENV NGINX_VERSION=1.13.8-…   0B                  
<missing>           2 weeks ago         /bin/sh -c #(nop)  LABEL maintainer=NGINX Do…   0B                  
<missing>           2 weeks ago         /bin/sh -c #(nop)  CMD ["bash"]                 0B                  
<missing>           2 weeks ago         /bin/sh -c #(nop) ADD file:f30a8b5b7cdc9ba33…   55.3MB

新的镜像定制好后,咱们能够来运行这个镜像。

$ docker run --name web2 -d -p 81:80 nginx:v2
ed8c54aeb3c540981b892c0cdfbf9330114ecc935149190e073f49295f2ae147

直接访问:http://localhost:81;若是使用的是 Docker Toolbox,或者是在虚拟机、云服务器上安装的 Docker,则须要将 localhost 换为虚拟机地址或者实际云服务器地址。

 Welcome to Docker!

使用 Dockerfile 定制镜像

从刚才的 docker commit 的学习中,咱们能够了解到,镜像的定制实际上就是定制每一层所添加的配置、文件。若是咱们能够把每一层修改、安装、构建、操做的命令都写入一个脚本,用这个脚原本构建、定制镜像,那么以前说起的没法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile

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

还以以前定制 nginx 镜像为例,此次咱们使用 Dockerfile 来定制。

在一个空白目录中,创建一个文本文件,并命名为 Dockerfile

$ mkdir mynginx
$ cd mynginx
$ touch Dockerfile

其内容为:

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

这个 Dockerfile 很简单,一共就两行。涉及到了两条指令,FROMRUN

FROM 指定基础镜像

所谓定制镜像,那必定是以一个镜像为基础,在其上进行定制。就像咱们以前运行了一个 nginx 镜像的容器,再进行修改同样,基础镜像是必须指定的。而 FROM 就是指定基础镜像,所以一个 DockerfileFROM 是必备的指令,而且必须是第一条指令。

Docker Store 上有很是多的高质量的官方镜像,有能够直接拿来使用的服务类的镜像,如 nginxredismongomysqlhttpdphptomcat 等;也有一些方便开发、构建、运行各类语言应用的镜像,如 nodeopenjdkpythonrubygolang 等。能够在其中寻找一个最符合咱们最终目标的镜像为基础镜像进行定制。

若是没有找到对应服务的镜像,官方镜像中还提供了一些更为基础的操做系统镜像,如 ubuntudebiancentosfedoraalpine 等,这些操做系统的软件库为咱们提供了更广阔的扩展空间。

除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为 scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。

FROM scratch
...

若是你以 scratch 为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将做为镜像第一层开始存在。

不以任何系统为基础,直接将可执行文件复制进镜像的作法并不罕见,好比 swarmcoreos/etcd。对于 Linux 下静态编译的程序来讲,并不须要有操做系统提供运行时支持,所需的一切库都已经在可执行文件里了,所以直接 FROM scratch 会让镜像体积更加小巧。使用 Go 语言 开发的应用不少会使用这种方式来制做镜像,这也是为何有人认为 Go 是特别适合容器微服务架构的语言的缘由之一。

RUN 执行命令

RUN 指令是用来执行命令行命令的。因为命令行的强大能力,RUN 指令在定制镜像时是最经常使用的指令之一。其格式有两种:

  • shell 格式:RUN <命令>,就像直接在命令行中输入的命令同样。刚才写的 Dockerfile 中的 RUN 指令就是这种格式。
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
  • exec 格式:RUN ["可执行文件", "参数1", "参数2"],这更像是函数调用中的格式。

既然 RUN 就像 Shell 脚本同样能够执行命令,那么咱们是否就能够像 Shell 脚本同样把每一个命令对应一个 RUN 呢?好比这样:

FROM debian:jessie

RUN apt-get update
RUN apt-get install -y gcc libc6-dev make
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz"
RUN mkdir -p /usr/src/redis
RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install

以前说过,Dockerfile 中每个指令都会创建一层,RUN 也不例外。每个 RUN 的行为,就和刚才咱们手工创建镜像的过程同样:新创建一层,在其上执行这些命令,执行结束后,commit 这一层的修改,构成新的镜像。

而上面的这种写法,建立了 7 层镜像。这是彻底没有意义的,并且不少运行时不须要的东西,都被装进了镜像里,好比编译环境、更新的软件包等等。结果就是产生很是臃肿、很是多层的镜像,不只仅增长了构建部署的时间,也很容易出错。 这是不少初学 Docker 的人常犯的一个错误。

Union FS 是有最大层数限制的,好比 AUFS,曾经是最大不得超过 42 层,如今是不得超过 127 层。

上面的 Dockerfile 正确的写法应该是这样:

FROM debian:jessie

RUN buildDeps='gcc libc6-dev make' \
    && apt-get update \
    && apt-get install -y $buildDeps \
    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \
    && mkdir -p /usr/src/redis \
    && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
    && make -C /usr/src/redis \
    && make -C /usr/src/redis install \
    && rm -rf /var/lib/apt/lists/* \
    && rm redis.tar.gz \
    && rm -r /usr/src/redis \
    && apt-get purge -y --auto-remove $buildDeps

首先,以前全部的命令只有一个目的,就是编译、安装 redis 可执行文件。所以没有必要创建不少层,这只是一层的事情。所以,这里没有使用不少个 RUN 对一一对应不一样的命令,而是仅仅使用一个 RUN 指令,并使用 && 将各个所需命令串联起来。将以前的 7 层,简化为了 1 层。在撰写 Dockerfile 的时候,要常常提醒本身,这并非在写 Shell 脚本,而是在定义每一层该如何构建。

而且,这里为了格式化还进行了换行。Dockerfile 支持 Shell 类的行尾添加 的命令换行方式,以及行首 # 进行注释的格式。良好的格式,好比换行、缩进、注释等,会让维护、排障更为容易,这是一个比较好的习惯。

此外,还能够看到这一组命令的最后添加了清理工做的命令,删除了为了编译构建所须要的软件,清理了全部下载、展开的文件,而且还清理了 apt 缓存文件。这是很重要的一步,咱们以前说过,镜像是多层存储,每一层的东西并不会在下一层被删除,会一直跟随着镜像。所以镜像构建时,必定要确保每一层只添加真正须要添加的东西,任何无关的东西都应该清理掉。

不少人初学 Docker 制做出了很臃肿的镜像的缘由之一,就是忘记了每一层构建的最后必定要清理掉无关文件。

构建镜像

好了,让咱们再回到以前定制的 nginx 镜像的 Dockerfile 来。如今咱们明白了这个 Dockerfile 的内容,那么让咱们来构建这个镜像吧。

Dockerfile 文件所在目录执行:

$ docker build -t nginx:v3 .

Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM nginx
 ---> 3f8a4339aadd
Step 2/2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
 ---> Running in 5cdac6d29a52
Removing intermediate container 5cdac6d29a52
 ---> 56a1b67b2533
Successfully built 56a1b67b2533
Successfully tagged nginx:v3

从命令的输出结果中,咱们能够清晰的看到镜像的构建过程。在 Step 2 中,如同咱们以前所说的那样,RUN 指令启动了一个容器 5cdac6d29a52,执行了所要求的命令,并最后提交了这一层 56a1b67b2533,随后删除了所用到的这个容器 5cdac6d29a52

这里咱们使用了 docker build 命令进行镜像构建。其格式为:

$ docker build [选项] <上下文路径/URL/->

镜像构建上下文(Context)若是注意,会看到 docker build 命令最后有一个 .. 表示当前目录

其它 docker build 的用法

直接用 Git repo 进行构建

或许你已经注意到了,docker build 还支持从 URL 构建,好比能够直接从 Git repo 中构建:

感谢:漠然提供 Git dockerfile repo

$ docker build https://github.com/mritd/dockerfile.git#:alpine-glibc
...

Executing ca-certificates-20171114-r0.post-deinstall
Executing busybox-1.27.2-r6.trigger
OK: 11 MiB in 14 packages
Removing intermediate container baf41e622959
 ---> aded3329be1b
Step 3/3 : ENV LANG=C.UTF-8
 ---> Running in 8c34e0f4d25b
Removing intermediate container 8c34e0f4d25b
 ---> c493a5aa5eb7
Successfully built c493a5aa5eb7

这行命令指定了构建所需的 Git repo,而且指定默认的 master 分支,构建目录为 /alpine-glibc/,而后 Docker 就会本身去 git clone 这个项目、切换到指定分支、并进入到指定目录后开始构建。

用给定的 tar 压缩包构建

$ docker build http://server/context.tar.gz

若是所给出的 URL 不是个 Git repo,而是个 tar 压缩包,那么 Docker 引擎会下载这个包,并自动解压缩,以其做为上下文,开始构建。

从标准输入中读取 Dockerfile 进行构建

$ docker build - < Dockerfile

$ cat Dockerfile | docker build -

若是标准输入传入的是文本文件,则将其视为 Dockerfile,并开始构建。这种形式因为直接从标准输入中读取 Dockerfile 的内容,它没有上下文,所以不能够像其余方法那样能够将本地文件 COPY 进镜像之类的事情。

从标准输入中读取上下文压缩包进行构建

$ docker build - < context.tar.gz

若是发现标准输入的文件格式是 gzip、bzip2 以及 xz 的话,将会使其为上下文压缩包,直接将其展开,将里面视为上下文,并开始构建。

参考:Docker — 从入门到实践

https://www.gitbook.com/download/pdf/book/yeasy/docker_practice

参考:Docker 官网 Get Docker CE for Ubuntu

https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/#install-using-the-convenience-script

Contact

  • 做者:鹏磊
  • 出处:http://www.ymq.io
  • Email:admin@souyunku.com
  • 版权归做者全部,转载请注明出处
  • Wechat:关注公众号,搜云库,专一于开发技术的研究与知识分享

关注公众号-搜云库

相关文章
相关标签/搜索