分布式缓存 — Docker

Docker 是一个开源项目,它基于 Google 公司推出的 Go 语言实现。 项目后来加入了 Linux 基金会,遵从了 Apache 2.0 协议,项目代码在 GitHub 上进行维护。

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。

Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案。 Docker 的基础是 Linux 容器(LXC)等技术。在 LXC 的基础上 Docker 进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便。用户操作 Docker 的容器就像操作一个快速轻量级的虚拟机一样简单。

下面的图片比较了 Docker 和传统虚拟化方式的不同之处,可见容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,而传统方式则是在硬件层面实现。

virtualization

docker

 

Docker 在如下几个方面具有较大的优势:

  • 更快速的交付和部署

Docker在整个开发周期都可以完美的辅助你实现快速交付。Docker允许开发者在装有应用和服务本地容器做开发。可以直接集成到可持续开发流程中。

例如:开发者可以使用一个标准的镜像来构建一套开发容器,开发完成之后,运维人员可以直接使用这个容器来部署代码。 Docker 可以快速创建容器,快速迭代应用程序,并让整个过程全程可见,使团队中的其他成员更容易理解应用程序是如何创建和工作的。 Docker 容器很轻很快!容器的启动时间是秒级的,大量地节约开发、测试、部署的时间。

  • 高效的部署和扩容

Docker 容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等。 这种兼容性可以让用户把一个应用程序从一个平台直接迁移到另外一个。

Docker的兼容性和轻量特性可以很轻松的实现负载的动态管理。你可以快速扩容或方便的下线的你的应用和服务,这种速度趋近实时。

  • 更高的资源利用率

Docker 对系统资源需求少,一台主机上可以同时运行数千个 Docker 容器。容器除了运行其中应用外,基本不消耗额外的系统资源,使得应用的性能很高,同时系统的开销尽量小。传统虚拟机方式运行 10 个不同的应用就要起 10 个虚拟机,而Docker 只需要启动 10 个隔离的应用即可。

  • 更简单的管理

使用 Docker,只需要小小的修改,就可以替代以往大量的更新工作。所有的修改都以增量的方式被分发和更新,从而实现自动化并且高效的管理。

 

Docker引擎

docker引擎是一个c/s结构的应用,主要组件见下图:

docker engine components flow

    • Server是一个常驻进程
    • REST API 实现了client和server间的交互协议
    • CLI 实现容器和镜像的管理,为用户提供统一的操作界面

Docker构架

Docker使用C/S架构,Client 通过接口与Server进程通信实现容器的构建,运行和发布。client和server可以运行在同一台集群,也可以通过跨主机实现远程通信。

支持三种连接方式:

  • unix:///var/run/docker.sock
  • tcp://host:port
  • fd://socketfd

docker architecture

 

核心概念

  • 镜像(image)

Docker 镜像(Image)就是一个只读的模板。例如:一个镜像可以包含一个完整的操作系统环境,里面仅安装了 Apache 或用户需要的其它应用程序。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。Docker 提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。

镜像(Image)就是一堆只读层(read-only layer)的统一视角,也许这个定义有些难以理解,看看下面这张图:

image ufs

右边我们看到了多个只读层,它们重叠在一起。除了最下面一层,其它层都会有一个指针指向下一层。这些层是Docker内部的实现细节,并且能够在docker宿主机的文件系统上访问到。统一文件系统(Union File System)技术能够将不同的层整合成一个文件系统,为这些层提供了一个统一的视角,这样就隐藏了多层的存在,在用户的角度看来,只存在一个文件系统。

  • 仓库(repository)

仓库(Repository)是集中存放镜像文件的场所。有时候会把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。

仓库分为公开仓库(Public)和私有仓库(Private)两种形式。最大的公开仓库是 Docker Hub,存放了数量庞大的镜像供用户下载。国内的公开仓库包括 时速云 、网易云 等,可以提供大陆用户更稳定快速的访问。当然,用户也可以在本地网络内创建一个私有仓库。

当用户创建了自己的镜像之后就可以使用 push 命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上 pull 下来就可以了。

Docker 仓库的概念跟 Git 类似,注册服务器可以理解为 GitHub 这样的托管服务。

  • 容器(container)

Docker 利用容器(Container)来运行应用。容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。

容器的定义和镜像几乎一模一样,也是一堆层的统一视角,唯一区别在于容器的最上面那一层是可读可写的。

container ufs

一个运行态容器被定义为一个可读写的统一文件系统加上隔离的进程空间和包含其中的进程。下面这张图片展示了一个运行中的容器。

Docker常用命令

搜索镜像:docker search

下载镜像:docker pull

docker pull centos:centos6
//实际上相当于 docker pull registry.hub.docker.com/centos:centos6命令,即从注册服务器 registry.hub.docker.com 中的 centos 仓库来下载标记为 centos6 的镜像。
//有时候官方仓库注册服务器下载较慢,可以从其他仓库下载。 从其它仓库下载时需要指定完整的仓库注册服务器地址。

查看已下载镜像列表:docker images

列出了所有顶层(top-level)镜像。实际上,在这里我们没有办法区分一个镜像和一个只读层,所以我们提出了top-level镜像。只有创建容器时使用的镜像或者是直接pull下来的镜像能被称为顶层(top-level)镜像,并且每一个顶层镜像下面都隐藏了多个镜像层。

$ docker images
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
centos                   centos6             6a77ab6655b9        8 weeks ago         194.6 MB
ubuntu                   latest              2fa927b5cdd3        9 weeks ago         122 MB

在列出信息中,可以看到几个字段信息

  • REPOSITORY:镜像来自于哪个仓库,比如 ubuntu
  • TAG:镜像的标签,比如 14.04。同一仓库可以有多个 TAG,代表这个仓库源的不同个版本,我们使用 REPOSTITORY:TAG 来定义不同的镜像。
  • IMAGE ID:镜像ID (唯一)
  • CREATED:创建时间
  • SIZE:镜像大小

给镜像添加标签:docker tag

docker tag daocloud.io/library/ubuntu:16.04 ubuntu:latest

利用 Dockerfile 来创建镜像:docker build

使用 docker commit 来扩展一个镜像比较简单,但是不方便在一个团队中分享。我们可以使用docker build 来创建一个新的镜像。

//首先需要创建一个 Dockerfile,包含一些如何创建镜像的指令。新建一个目录和一个 Dockerfile。
mkdir hainiu
cd hainiu
touch Dockerfile

//Dockerfile 中每一条指令都创建镜像的一层,例如:
FROM centos:centos6
MAINTAINER sandywei <sandy@hainiu.tech>
# move all configuration files into container

RUN yum install -y httpd
EXPOSE 80
CMD ["sh","-c","service httpd start;bash"]

Dockerfile 基本的语法:

  • 使用#来注释
  • FROM 指令告诉 Docker 使用哪个镜像作为基础
  • 接着是维护者的信息
  • RUN开头的指令会在创建中运行,比如安装一个软件包,在这里使用yum来安装了一些软件

编写完成 Dockerfile 后可以使用 docker build 来生成镜像。

$ docker build -t hainiu/httpd:1.0 .

Sending build context to Docker daemon 2.048 kB
Step 1 : FROM centos:centos6
 ---> 6a77ab6655b9
Step 2 : MAINTAINER sandywei <sandy@hainiu.tech>
 ---> Running in 1b26493518a7
 ---> 8877ee5f7432
Removing intermediate container 1b26493518a7
Step 3 : RUN yum install -y httpd
 ---> Running in fe5b6f1ef888

 .....

 Step 5 : CMD sh -c service httpd start
 ---> Running in b2b94c1601c2
 ---> 5f9aa91b0c9e
Removing intermediate container b2b94c1601c2
Successfully built 5f9aa91b0c9e
# 其中 -t 标记来添加 tag,指定新的镜像的用户信息。 “.” 是 Dockerfile 所在的路径(当前目录),也可以替换为一个具体的 Dockerfile 的路径。注意一个镜像不能超过 127 层

用docker images 查看镜像列表

$ docker images
REPOSITORY                 TAG               IMAGE ID            CREATED             SIZE
hainiu/httpd               1.0               5f9aa91b0c9e        3 minutes ago       292.4 MB
centos                   centos6             6a77ab6655b9        8 weeks ago         194.6 MB
ubuntu                   latest              2fa927b5cdd3        9 weeks ago         122 MB
# 细心的朋友可以看到最后一层的ID(5f9aa91b0c9e)和 image id 是一样的

上传镜像:docker push

用户可以通过 docker push 命令,把自己创建的镜像上传到仓库中来共享。例如,用户在 Docker Hub 上完成注册后,可以推送自己的镜像到仓库中。

$ docker push hainiu/httpd:1.0

创建容器:docker create <image-id>

docker create 命令为指定的镜像(image)添加了一个可读写层,构成了一个新的容器。注意,这个容器并没有运行。

docker create 命令提供了许多参数选项可以指定名字,硬件资源,网络配置等等。

这个功能在进行测试的时候十分方便,比如用户可以放置一些程序到本地目录中,来查看容器是否正常工作。本地目录的路径必须是绝对路径,如果目录不存在 Docker 会自动为你创建它。

//创建一个centos的容器,可以使用仓库+标签的名字确定image,也可以使用image-id指定image。返回容器id
#查看本地images列表
$ docker images

#用仓库+标签
$ docker create -it --name centos6_container centos:centos6

#使用image-id
$ docker create -it --name centos6_container 6a77ab6655b9 bash
b3cd0b47fe3db0115037c5e9cf776914bd46944d1ac63c0b753a9df6944c7a67

#可以使用 docker ps查看一件存在的容器列表,不加参数默认只显示当前运行的容器
$ docker ps -a
//可以使用 -v 参数将本地目录挂载到容器中。 $ docker create -it --name centos6_container -v /src/webapp:/opt/webapp centos:centos6

启动容器:docker start <container-id>

Docker start命令为容器文件系统创建了一个进程隔离空间。注意,每一个容器只能够有一个进程隔离空间。

#通过名字启动
$ docker start -i centos6_container

#通过容器ID启动
$ docker start -i b3cd0b47fe3d

进入容器:docker exec <container-id>

//在当前容器中执行新命令,如果增加 -it参数运行bash 就和登录到容器效果一样的。
docker exec -it centos6_container bash

停止容器:docker stop <container-id>

删除容器:docker rm <container-id>

运行容器:docker run <image-id>

docker run就是docker create和docker start两个命令的组合,支持参数也是一致的,如果指定容器名字是,容器已经存在会报错,可以增加 --rm 参数实现容器退出时自动删除。

docker create -it --rm --name centos6_container centos:centos6

查看容器列表:docker ps

docker ps 命令会列出所有运行中的容器。这隐藏了非运行态容器的存在,如果想要找出这些容器,增加 -a 参数。

删除镜像:docker rmi <image-id>

删除构成镜像的一个只读层。你只能够使用docker rmi来移除最顶层(top level layer)(也可以说是镜像),你也可以使用-f参数来强制删除中间的只读层。

commit容器:docker commit <container-id>

将容器的可读写层转换为一个只读层,这样就把一个容器转换成了不可变的镜像。

镜像保存:docker save <image-id>

创建一个镜像的压缩文件,这个文件能够在另外一个主机的Docker上使用。和export命令不同,这个命令为每一个层都保存了它们的元数据。这个命令只能对镜像生效。

#保存centos镜像到centos_images.tar 文件
$ docker save  -o centos_images.tar centos:centos6

#或者直接重定向
$ docker save  -o centos_images.tar centos:centos6 > centos_images.tar

导入镜像:docker load

docker load --input ubuntu_latest.tar
# 或者
docker load < ubuntu_latest.tar

容器导出:docker export <container-id>

创建一个tar文件,并且移除了元数据和不必要的层,将多个层整合成了一个层,只保存了当前统一视角看到的内容。expoxt后的容器再import到Docker中,只有一个容器当前状态的镜像;而save后的镜像则不同,它能够看到这个镜像的历史镜像。

提取出容器或者镜像最顶层的元数据:docker inspect <container-id> or <image-id>

 

Dockerfile文件语法

FROM(指定基础image)

构建指令,必须指定且需要在Dockerfile其他指令的前面。后续的指令都依赖于该指令指定的image。FROM指令指定的基础image可以是官方远程仓库中的,也可以位于本地仓库。镜像可以指定标签。格式:

FROM <image>:<tag> 

MAINTAINER(用来指定镜像创建者信息)
构建指令,用于将image的制作者相关的信息写入到image中。当我们对该image执行docker inspect命令时,输出中有相应的字段记录该信息。

MAINTAINER <name> 

RUN
构建指令,RUN可以运行任何被基础image支持的命令。如基础image选择了ubuntu,那么软件管理部分只能使用ubuntu的命令。RUN指令可以有多条,每条RUN指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时,可以用\来换行。

该指令有两种格式:

# 在shell终端中运行 - `/bin/sh -c`
RUN <command>

# 使用exec执行
RUN ["executable", "param1", "param2" ... ]

CMD(设置容器启动时执行的操作)
设置指令,用于容器启动时指定的操作。该操作可以是执行自定义脚本,也可以是执行系统命令。该指令只能在文件中存在一次,如果有多个,则只执行最后一条。

该指令有三种格式:

# 格式一: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"]
注意:
1) CMD运行在镜像构建之后,容器启动的时候;
2) CMD只执行最后一条
3) CMD可以被用户指定的命令覆盖

ENTRYPOINT(设置容器启动时执行的操作)
设置指令,指定容器启动时执行的命令,可以多次设置,但是只有最后一个有效。

两种格式:

# 格式一:like an exec, this is the preferred form
ENTRYPOINT ["executable", "param1", "param2"]

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

该指令的使用分为两种情况,一种是独自使用,另一种和CMD指令配合使用。

当独自使用时,如果你还使用了CMD命令且CMD是一个完整的可执行的命令,那么CMD指令和ENTRYPOINT会互相覆盖只有最后一个CMD或者ENTRYPOINT有效:

# CMD指令将不会被执行,只有ENTRYPOINT指令被执行 
CMD echo “Hello, World!” 
ENTRYPOINT ls -l 

另一种用法和CMD指令配合使用来指定ENTRYPOINT的默认参数,这时CMD指令不是一个完整的可执行命令,仅仅是参数部分;ENTRYPOINT指令只能使用JSON方式指定执行命令,而不能指定参数:

FROM ubuntu 
CMD ["-l"] 
ENTRYPOINT ["/usr/bin/ls"] 
注意:
1) 和CMD指令基本一样,但是不能被用户指定的命令所覆盖
2) 可以和CMD组合使用,ENTRYPOINT提供不可变的命令,CMD提供缺省参数

USER(设置容器的用户)
设置指令,设置启动容器的用户,默认是root用户。

# 指定memcached的运行用户 
ENTRYPOINT ["memcached"] 
USER daemon 
# 或 
ENTRYPOINT ["memcached", "-u", "daemon"] 

EXPOSE(指定容器需要映射到宿主机器的端口)
设置指令,该指令会将容器中的端口映射成宿主机器中的某个端口。格式为:EXPOSE <port> [<port> ...]

EXPOSE 80 443 11211 

告诉Docker服务端容器暴露的端口号,供互联系统使用。在启动容器时需要通过-P,Docker主机会自动分配一个端口转发到指定的端口;使用-p,则可以具体指定哪个本地端口映射过来。

ENV(用于设置环境变量)

构建指令,在image中设置一个环境变量。格式:ENV <key> <value>
设置了后,后续的RUN命令都可以使用,容器启动后,可以通过docker inspect查看这个环境变量,也可以通过在docker run --env key=value时设置或修改环境变量。
假如你安装了JAVA程序,需要设置JAVA_HOME,那么可以在Dockerfile中这样写:

ENV JAVA_HOME /path/to/java/dirent

ADD(从src复制文件到容器的dest路径)

构建指令,所有拷贝到容器中的文件和文件夹权限为0755,uid和gid为0。格式为:ADD <src> <dest>
<src> 是相对被构建的源目录的相对路径,可以是文件或目录的路径,也可以是一个远程的文件url;<dest>是容器中的绝对路径。
该命令将复制指定的<src>到容器中的<dest>。其中<src>可以是Dockerfile所在目录的一个相对路径(文件或目录);也可以是一个URL;还可以是一个tar文件(自动解压为目录)。
如果是一个目录,那么会将该目录下的所有文件添加到容器中,不包括目录;如果文件是可识别的压缩格式,则docker会帮忙解压缩(注意压缩格式);如果<src>是文件且<dest>中不使用斜杠结束,则会将<dest>视为文件,<src>的内容会写入<dest>;如果<src>是文件且<dest>中使用斜杠结束,则会<src>文件拷贝到<dest>目录下。

COPY

格式:COPY <src> <dest>
复制本地主机的<src>(为Dockerfile所在目录的相对路径,文件或目录)为容器中的<dest>。目标路径不存在时,会自动创建。
当使用本地目录为源目录时,推荐使用COPY。

VOLUME(指定挂载点))
设置指令,使容器中的一个目录具有持久化存储数据的功能,该目录可以被容器本身使用,也可以共享给其他容器使用。我们知道容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。当容器中的应用有持久化数据的需求时可以在Dockerfile中使用该指令。格式:VOLUME ["<mountpoint>"] 

FROM base 
VOLUME ["/tmp/data"] 

运行通过该Dockerfile生成image的容器,/tmp/data目录中的数据在容器关闭后,里面的数据还存在。例如另一个容器也有持久化数据的需求,且想使用上面容器共享的/tmp/data目录,那么可以运行下面的命令启动一个容器:

docker run -t -i -rm -volumes-from container1 image2 bash 
# container1为第一个容器的ID,image2为第二个容器运行image的名字

WORKDIR(切换目录)
设置指令,可以多次切换(相当于cd命令),对RUN,CMD,ENTRYPOINT生效。格式:WORKDIR /path/to/workdir 

# 在 /p1/p2 下执行 vim a.txt 
WORKDIR /p1
WORKDIR p2
RUN vim a.txt 

ONBUILD(在子镜像中执行)

ONBUILD 指定的命令在构建镜像时并不执行,而是在它的子镜像中执行。格式:ONBUILD <Dockerfile关键字> 

ARG(指定构建过程中使用的环境变量)

ARG buildno
ARG password

RUN echo "Build number: $buildno"
RUN script-requiring-password.sh "$password"

 

整理自:https://www.cnblogs.com/SzeCheng/p/6822905.html、https://blog.csdn.net/xiaochendefendoushi/article/details/80979905

posted @ 2019-05-31 18:51  WhatAreWords  阅读(308)  评论(0编辑  收藏  举报