zoukankan      html  css  js  c++  java
  • Docker学习笔记——制作容器与容器概念

    Docker能做些什么?

    1.docker能够解决虚拟机能够解决的问题

    2.隔离应用依赖

    3.创建应用镜像并复制

    4.创建容易分发的即启即用的应用

    5.docker的想法是创建软件程序可移植的轻量容器

    镜像

    1.docker的镜像类似虚拟机的快照

    2.在现有镜像的基础上创建镜像


    容器

    1.可以从镜像中创建容器

    2.容器和虚拟机一样是隔离的,它也拥有一个唯一ID和唯一供读人的名字,docker允许公开容器的公开端口

    3.容器是被来设计运行一个应用的 而不是一台机器

    4.容器应该是短暂和一次性的

    链接:

    1.容器启动时将会被分配一个私有IP,其他容器可以使用这个IP与其进行通讯,因此,容器可以共享一个本地网络

    2.docker允许你在创建一个新容器时引用其他现存容器,在你刚创建的容器中被引用的容器会获得一个别名,我们就可以定义 ,这两个容器链接在了一起。

    3.比如一个DB容器已经在运行,我们创建web容器的时候引用这个DB容器,给它起一个别名叫做dbapp,那么在这个新建的web容器中,我们可以在任何时候使用主机名dbapp和DB通信

    docker的两样法宝

    Cgroups

    作用:

    限制linux进程组的资源占用

    为进程组制作PIDS,UTS,IPC,网络和装载命名空间

    Cgroup创建一个环境,进程可以在其中运行,并与操作系统的其他进程进行隔开

    容器runtime

    容器runtime是容器真正运行的地方,runtime需要和操作系统kernel紧密结合,为容器提供运行环境。

    比如说,java程序比作一个容器,JVM就是runtime。JVM为java程序提供运行环境。

    所以容器只能在runtime里面运行

     

    lxc、runc 和 rkt 是目前主流的三种容器 runtime。

    lxc 是 Linux 上老牌的容器 runtime。Docker 最初也是用 lxc 作为 runtime。

    runc 是 Docker 自己开发的容器 runtime,符合 oci 规范,也是现在 Docker 的默认 runtime。

    rkt 是 CoreOS 开发的容器 runtime,符合 oci 规范,因而能够运行 Docker 的容器。

    容器管理工具

    除了运行环境,使用者也得需要工具来管理容器。容器管理工具对内与runtime交互,对外为用户提供interface.

    lxd是lxc对应的容器管理工具;runc的管理工具是docker engine。docker engine 包含后台 deamon 和 cli 两个部分。我们通常提到 Docker,一般就是指的 docker engine。rkt 的管理工具是 rkt cli。

    容器定义工具

    容器定义工具允许用户定义容器的内容属性,这样容器就能够被保存,共享和重建

    docker image 是 docker 容器的模板,runtime 依据 docker image 创建容器。

    dockerfile 是包含若干命令的文本文件,可以通过这些命令创建出 docker image。

    ACI (App Container Image) 与 docker image 类似,只不过它是由 CoreOS 开发的 rkt 容器的 image 格式。

    仓库Registy

    容器是通过image创建的,需要一个仓库统一存放image,这个仓库就叫做Registy

     企业可以用 Docker Registry 构建私有的 Registry。

    Docker Hub(https://hub.docker.com )是 Docker 为公众提供的托管 Registry,上面有很多现成的 image,为 Docker 用户提供了极大的便利。

    Quay.io(https://quay.io/  )是另一个公共托管 Registry,提供与 Docker Hub 类似的服务。

     容器OS

    因为容器有runtime,所以几乎所有的linux、MAC OS和windows都可以运行容器

    容器 OS 是专门运行容器的操作系统。与常规 OS 相比,容器 OS 通常体积更小,启动更快。因为是为容器定制的 OS,通常它们运行容器的效率会更高。

    目前已经存在不少容器 OS,CoreOS、atomic 和 ubuntu core 是其中的杰出代表。

    容器平台技术

    容器核心技术能够让让容器在单个主机上运行,容器平台技术能够让容器作为集群在分布式环境中运行。容器平台技术如下图:

    分为容器编排技术、容器管理平台、基于容器的PaaS。

    容器编排引擎

    基于容器的应用一般会采用微服务架构。在这中间架构下,应用被划分成不同的组件,并以服务的方式运行在各个容器中,通过API对外提供服务,为了保证服务的高可用,每个组件会运行多个相同的容器。

    这些容器会组成集群,集群中的容器会根据业务动态的创建、迁移和销毁。

    这样基于微服务架构的系统实际上是一个动态可伸缩的系统。容器编排引擎就排上用场了。

    编排(orchestration),通常包括容器管理、调度、集群定义和服务发现。通过容器编排引擎、容器被有机的组合成微服务应用,实现业务需求。

    docker swarm 是 Docker 开发的容器编排引擎。

    kubernetes 是 Google 领导开发的开源容器编排引擎,同时支持 Docker 和 CoreOS 容器。

    mesos 是一个通用的集群资源调度平台,mesos 与 marathon 一起提供容器编排引擎功能。

    以上三者是当前主流的容器编排引擎。

    容器管理平台

    容器管理平台是在容器编排引擎之上的一个更为通用的平台。通常容器管理平台能够支持多个编排引擎,抽象了编排引擎的底层实现细节。

    比如:application catalog和一键应用部署

    Rancher和Containership是容器管理平台的典型代表

    容器支持技术

     容器网络

     容器使得网络变得复杂,用户需要专门的解决方案来管理容器与容器,容器与其他实体之间的连通性和隔离性。

    docker network是docker原生的解决方案。

    服务发现

    微服务的最大特点是动态变化,当负载增加时,集群会自动创建新的容器;负载减小,多余的容器就会被销毁。容器也会根据主机的资源情况在不同主机上迁移,容器的IP和端口也随之改变。

    在这种情况下,必须要让客户端能够知道如何访问容器提供的服务。这就是服务发现的工作。

    服务发现会保存集群中所有微服务的最新信息,比如IP和端口,对外提供的API,提供服务和查询等。

    比较主流的是etcd,consul,zookeeper。

    制作第一个容器

    准备这些条件:

    1.一个Ubuntu系统

    2.这个系统能够联网,最起码ping www.baidu.com是可以的

    这些准备条件准备好了,接下来就开始做准备工作。

    Docker 分为开源免费的 CE(Community Edition)版本和收费的 EE(Enterprise Edition)版本。下面我们将按照文档,通过以下步骤在 Ubuntu 16.04 上安装 Docker CE 版本。

    这里下载的是CE版本。

    配置Docker的apt源

    打开ubuntu虚拟机,ping 一下百度

    OK,可以的,因为制作容器的过程中需要联网,这个条件是必要的。

    1.安装包,允许 apt 命令 HTTPS 访问 Docker 源。执行命令:

    sodo apt-get install apt-transport-https ca-certificate curl software-properties-common

     然后会下载一些东西,等待下载完成即可

    2.添加 Docker 官方的 GPG
    sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

    3.将Docker的源添加到/etc/apt/source.list

    sodu add-apt-repository  "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs)  stable"

    4.刷新apt源

    sudo apt-get update

    5.安装Docker

    sudo apt-get install docker-ce

    这步完成之后,Docker也就安装完成了,是不是很简单,接下来就是如何使用Dokcer的问题了。

    下载你的第一个容器:

    docker run -d -p 80:80 httpd

    这个过程是,首先docker发现主机上没有http,然后就会去下载(镜像中已经安装好了 Apache HTTP Server),下载完毕之后再运行运行,将容器的80端口映射到主机的80端口。

    接下来检测一下容器是否正常运行,浏览器中输入该主机的IP,我这里是192.168.90.71

    OK,web服务器运行成功!

    Docker的第一个helloworld也就大功告成!

    什么是容器?

    容器是一个自包含,可移植,轻量级的软件打包技术。是应用程序在任何地方几乎以相同方式运行。开发人员在开发机上创建好容器,无需任何修改就能在虚拟机,云服务器或公有云主机上运行。

    容器与虚拟机

    容器有两部分组成:

    1.应用程序本身

    2.应用程序所依赖的环境,库

    容器在主机中运行,与操作系统中其他的进程隔离,这一点区别于虚拟机。

    传统的虚拟机技术,如:vmvare,他是创建一个完整的虚拟机,为了运行应用程序,部署系统,还需要安装整个操作系统(几十GB),

    下图展示了两者的区别:

    从右图中可以看见,所有容器都共享一个系统,对于虚拟机来说,都是一个单独的系统。

    启动容器不需要启动整个系统,所以容器部署和启动速度更快,开销更小,也更容易迁移。

    为什么要使用容器技术?

    因为方便。这取决于容器使得软件具备超强的可移植能力。

    现如今软件开发的部署相对于以前来说,要复杂很多,开发人员需要使用多种服务构建和组装应用,而且系统还可能会部署到不同的环境中。

    而且这个服务都有自己依赖的库和环境,还有可能存在着动态迁移到不同的环境中。

    大家做过软件开发的都知道,软件部署是一件很麻烦的事情,那么有没有一种技术使得软件部署很平滑呢?

    开发人员受到了集装箱的启发。

    以前运送货物,会担心货物类型不同而担心损失,比如运送的食物被其他货物压坏了。后来人们发明了集装箱,标准集装箱可以被高效地装卸、重叠和长途运输。现代化的起重机可以自动在卡车、轮船和火车之间移动集装箱。集装箱被誉为运输业与世界贸易最重要的发明。

    Docker 将集装箱思想运用到软件打包上,为代码提供了一个基于容器的标准化运输系统。Docker 可以将任何应用及其依赖打包成一个轻量级、可移植、自包含的容器。容器可以运行在几乎所有的操作系统上。

    容器意味着环境隔离和可重复性。开发人员只需为应用创建一次运行环境,然后打包成容器便可在其他机器上运行。另外,容器环境与所在的 Host 环境是隔离的,就像虚拟机一样,但更快更简单。

    Docker的核心组件:

    1.Docker客户端 - Client

    2.Docker服务器 - Docker deamon

    3.Docker镜像 - Image

    4.仓库 - Registry

    5.Docker容器 - Container

    Docker架构图如下:

    Docker采用的是C/S架构,客户端向服务器发送请求,服务器负责创建、运行和分发容器。

    Docker客户端:

    Docker客户端的命令如下:

    Docker服务器:

    Docker deamon是服务器组件,以Linux后台服务方式运行。

    Docker daemon 运行在 Docker host 上,负责创建、运行、监控容器,构建、存储镜像。

    默认配置下,Docker daemon 只能响应来自本地 Host 的客户端请求。如果要允许远程客户端请求,需要在配置文件中打开 TCP 监听,步骤如下:

      1.编辑配置文件 /etc/systemd/system/multi-user.target.wants/docker.service,在环境变量 -H tcp://0.0.0.0,允许来自任意 IP 的客户端连接。

      2.重启 Docker daemon。

      3.服务器 IP 为 192.168.56.102,客户端在命令行里加上 -H 参数,即可与远程服务器通信

     

    Docker镜像 :

    可将Docker镜像看成一个只读模板。一个镜像里可能含有一个系统,或者一个Tomcat。

    镜像有多种生成方法:

    1. 可以从无到有开始创建镜像

    2. 也可以下载并使用别人创建好的现成的镜像

    3. 还可以在现有镜像上创建新的镜像

    我们可以将镜像的内容和创建步骤描述在一个文本文件中,这个文件被称作 Dockerfile,通过执行 docker build <docker-file> 命令可以构建出 Docker 镜像。

    Docker容器:

    Docker容器就是Docker运行的环境。对于软件而言,镜像像是生命周期的构建和打包阶段,容器则是启动和运行阶段。

    Docker仓库Registry:

    镜像有多种生成方法:

    1. 可以从无到有开始创建镜像

    2. 也可以下载并使用别人创建好的现成的镜像

    3. 还可以在现有镜像上创建新的镜像

    我们可以将镜像的内容和创建步骤描述在一个文本文件中,这个文件被称作 Dockerfile,通过执行 docker build <docker-file> 命令可以构建出 Docker 镜像.

    docker pull 命令是从Registry下载镜像

    docker run命令是先下载镜像 然后再启动容器

    下面看一个运行实例:

    1. Docker 客户端执行 docker run 命令。

    2. Docker daemon 发现本地没有 httpd 镜像。

    3. daemon 从 Docker Hub 下载镜像。

    4. 下载完成,镜像 httpd 被保存到本地。

    5. Docker daemon 启动容器。

    docker images 可以看下已经下载到本地的镜像。

    dokcer ps 可以查看哪些容器正在运行

    镜像的分层结构:

    实际上,Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。比如我们现在构建一个新的镜像,Dockerfile 如下:

    ① 新镜像不再是从 scratch 开始,而是直接在 Debian base 镜像上构建。
    ② 安装 emacs 编辑器。
    ③ 安装 apache2。
    ④ 容器启动时运行 bash。

     构建过程如下图所示:

    可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。

    问什么 Docker 镜像要采用这种分层结构呢?

    最大的一个好处就是 - 共享资源

    比如:有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享,我们将在后面更深入地讨论这个特性。

    这时可能就有人会问了:如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如 /etc 下的文件,这时其他容器的 /etc 是否也会被修改?

    答案是不会!
    修改会被限制在单个容器内。因为容器的Copy-on-Write特性

    可写的容器层

    当容器启动时,一个新的可写层被加载到镜像的顶部。
    这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。

    所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。

      1. 添加文件
        在容器中创建文件时,新文件被添加到容器层中。

      2. 读取文件 在容器中读取某个文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后打开并读入内存。

      3. 修改文件 在容器中修改已存在的文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后修改之。

      4. 删除文件 在容器中删除文件时,Docker 也是从上往下依次在镜像层中查找此文件。找到后,会在容器层中记录下此删除操作。

     

    只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改。

    这样就解释了我们前面提出的问题:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享

     

    如何构建镜像

    使用现成镜像的好处除了省去自己做镜像的工作量外,更重要的是可以利用前人的经验。特别是使用那些官方镜像,因为 Docker 的工程师知道如何更好的在容器中运行软件。

    当然,某些情况下我们也不得不自己构建镜像,比如:

    1. 找不到现成的镜像,比如自己开发的应用程序。

    2. 需要在镜像中加入特定的功能,比如官方镜像几乎都不提供 ssh。

    所以本节我们将介绍构建镜像的方法。同时分析构建的过程也能够加深我们对前面镜像分层结构的理解。

    Docker 提供了两种构建镜像的方法:

    1. docker commit 命令

    2. Dockerfile 构建文件

    Docker官方推荐使用Dockerfile构建镜像。

     镜像缓存

    Docker 会缓存已有镜像的镜像层,构建新镜像时,如果某镜像层已经存在,就直接使用,无需重新创建。

    Dockerfile 中每一个指令都会创建一个镜像层,上层是依赖于下层的。无论什么时候,只要某一层发生变化,其上面所有层的缓存都会失效。

    也就是说,如果我们改变 Dockerfile 指令的执行顺序,或者修改或添加指令,都会使缓存失效。

     DockerFile

    Dockerfile指令说明

    指令

    说明

    用法

    FROM

    指定base镜像

    两种用法:

    1.FROM <image>

    指定基础image为该image的最后修改的版本

    2.FROM <image>:<tag>

    指定基础image为该image的一个tag版本。

    MAINTAINER

    设置镜像的作者,用于将image的制作者相关的信息写入到image中

    MAINTAINER <name>

    RUN

    在容器中运行制定的命令,

    一般用于装软件

    两种格式:

    1.RUN <command> (the command is run in a shell - `/bin/sh -c`)  

    2.RUN ["executable", "param1", "param2" ... ]  (exec form)

    CMD

    (设置container启动时执行的操作)

    三种方式

    1. CMD ["executable","param1","param2"]   2.CMD command param1 param2 (as a shell)

    第三种方式:当指定了ENTRYPOINT,那么使用下面的格式

    CMD ["param1","param2"] (as default parameters to ENTRYPOINT)

      
    ENTRYPOINT指定的是一个可执行的脚本或者程序的路径,该指定的脚本或者程序将会以param1和param2作为参数执行。所以如果CMD指令使用上面的形式,那么Dockerfile中必须要有配套的ENTRYPOINT。

    ENTRYPOINT

    配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。

    每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。

    ENTRYPOINT ["executable", "param1", "param2"] (like an exec, the preferred form)  

    ENTRYPOINT command param1 param2 (as a shell)  

    该指令的使用分为两种情况,一种是独自使用,另一种和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"]

    EXPOSE

    设置指令,该指令会将容器中的端口映射成宿主机器中的某个端口。当你需要访问容器的时候,可以不是用容器的IP地址而是使用宿主机器的IP地址和映射后的端口。要完成整个操作需要两个步骤,首先在Dockerfile使用EXPOSE设置需要映射的容器端口,然后在运行容器的时候指定-p选项加上EXPOSE设置的端口,这样EXPOSE设置的端口号会被随机映射成宿主机器中的一个端口号。

    EXPOSE <port> [<port>...]  

    ENV

    用于设置环境变量

    设置了后,后续的RUN命令都可以使用,容器启动后,可以通过docker inspect查看这个环境变量,也可以通过在docker run --env key=value时设置或修改环境变量。

    假如你安装了JAVA程序,需要设置JAVA_HOME,那么可以在Dockerfile中这样写:

    ENV JAVA_HOME /path/to/java/dirent

    ADD

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

    如果是一个目录,那么会将该目录下的所有文件添加到容器中,不包括目录;如果文件是可识别的压缩格式,则docker会帮忙解压缩(注意压缩格式)

    ADD  <src>  <dist>

    <src>是相对被构建的源目录的相对路径,可以是文件或目录的路径,也可以是一个远程的文件url;

    <dist>是容器的绝对路径

    VOLUMN

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

    VOLUME ["<mountpoint>"]  

    例:

    FROM unbuntu

    VOLUMN [“/tmp/data”]运行通过该Dockerfile生成image的容器,/tmp/data目录中的数据在容器关闭后,里面的数据还存在。

    WORKDIR

    可以多次切换(相当于cd命令),对RUN,CMD,ENTRYPOINT生效。

    例:# 在 /p1/p2 下执行 vim a.txt  

        WORKDIR /p1 WORKDIR p2 RUN vim a.txt  

     

     

  • 相关阅读:
    动态规划之最大子段和问题
    hdu1203 I NEED A OFFER!---概率DP(01背包)
    hdu1087 Super Jumping! Jumping! Jumping!---基础DP---递增子序列最大和
    hdu2062 Subset sequence----递推
    java线程基础巩固---通过实验分析This锁和Class锁的存在
    java8学习之BiFunction函数式接口实例演示&Predicate函数式接口详解
    java8学习之Function与BiFunction函数式接口详解
    java8学习之Lambda表达式继续探讨&Function接口详解
    java8学习之Lambda表达式深入与流初步
    java8学习之深入函数式接口与方法引用
  • 原文地址:https://www.cnblogs.com/superfj/p/7927651.html
Copyright © 2011-2022 走看看