docker

 

docker

什么是docker

Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源。 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。 容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。 传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。

传统虚拟机和docker对比

 

特性

容器

  

虚拟机
启动  秒级 分钟级
硬盘使用 一般为MB 一般为GB
性能 接近原生 弱与原生
系统支持量 单机支持上千个容器 一般几十个









为什么要使用Docker

  • 更高效的利用系统资源
  • 更快速的启动时间
  • 一致的运行环境
  • 持续交付和部署
  • 更轻松的迁移
  • 更轻松的维护和扩展


Docker的应用场景

  • Web 应用的自动化打包和发布。
  • 自动化测试和持续集成、发布。
  • 在服务型环境中部署和调整数据库或其他的后台应用。
  • 从头编译或者扩展现有的OpenShift或Cloud Foundry平台来搭建自己的PaaS环境

Docker的三个基本概念

  • 镜像(Image)
  • 容器(Container) 
  • 仓库(Repository)

理解了这三个概念,就理解了 Docker 的整个生命周期。转换下思路:

Docker 面向对象
容器 对象
镜像
仓库 代码仓库

Docker架构

 

 

 Docker-使用镜像

镜像是 Docker 的三大组件之一,Docker 运行容器前需要本地存在对应的镜像,如果本地不存在该镜像,Docker 会从镜像仓库下载该镜像。

获取镜像:

docker pull [选项] [Docker Registry 地址:端口号/]仓库名[:标签]

Docker 镜像仓库地址:

地址的格式一般是 <域名/IP>[:端口号]。默认地址是 Docker Hub。 仓库名:如之前所说,这里的仓库名是两段式名称,即 <用户名>/<软件名>。对于 Docker Hub,如果不给出用户名,则默认为 library,也就是官方镜像。

示例:docker pull redis   --默认从官网拉取redis镜像

docker pull redis:5.0-rc6   --默认从官网拉取redis:5.0-rc6镜像,不同版本号的redis镜像

运行镜像:

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

docker run -d -p 6379:6379 --name yvesredis redis

如果在docker run 后面追加-d=true或者-d,则containter将会运行在后台模式(Detached mode)。此时所有I/O数据只能通过网络资源或者共享卷组来进行交互

--name 如果你在执行docker run时没有指定 --name,那么deamon会自动生成一个随机数字符串当做UUID。但是对于一个container来说有个name会非常方便,因为你可以当你需要link其它容器时或者其他类似需要区分其它容器时,使用容器名称会简化操作。无论container运行在前台或者后台,这个名字都是有效的

Image[:tag]  当一个image的名称不足以分辨这个image所代表的含义时,你可以通过tag将版本信息添加到run 命令中来执行特定版本的image。例如: docker run redis:5.0-rc6 

-p :端口映射,将容器的端口映射到本地端口

查看所有镜像

docker image ls  (显示顶层镜像)或者docker images(相当于docker image ls -a 显示所有镜像)

看镜像、容器、数据卷所占用的空间:docker system df 

 

虚悬镜像(dangling image) :镜像既没有仓库名,也没有标签,均为 <none>

列出虚悬镜像:docker image ls -f dangling=true

删除虚悬镜像:docker image prune

删除本地镜像:docker rmi 镜像名称

Ls命令配合删除:docker image rm $(docker image ls -q hello-world)   删除所有hello-word镜像

 

镜像迁移(保存层数据):

docker save image:tag -o /root/name.tar

docker load -i /root/name.tar

镜像迁移(不保存层数据):

docker export –o /root/name.tar

docker import /root/name.tar

-o, --output string Write to a file, instead of STDOUT 写入到文件中,而不是标准输出流

用户既可以使用 docker load 来导入镜像存储文件到本地镜像库,也可以使用 docker import 来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。此外,从容器快照文件导入时可以重新指定标签等元数据信息

Docker-使用容器

容器是 Docker 又一核心概念。 简单的说,容器是独立运行的一个或一组应用,以及它们的运行态环境。对应的,虚拟机可以理解为模拟运行的一整套操作系统(提供了运行态环境和其他系统环境)和跑在上面的应用。

启动 启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(stopped)的容器重新启动。

 新建并启动:docker run -d --name yvesredis redis

启动已停止容器:docker start yvesredis

停止容器 :docker stop yvesredis

查看容器信息:docker container ls  或者docker ps  (查看正在运行的容器  -a 代表查看所有容器,包括已停止的)

获取容器的输出信息:docker container logs container/xxid(容器名称或者容器ID)

进入容器:docker exec -it 容器id/容器名 bash

导出容器:docker export 容器id > ubuntu.tar

导入容器快照: cat ubuntu.tar | docker import - test/ubuntu:v1.0

示例:cat yvesredis.tar | docker import - testredis

删除容器:docker container rm id/name

清理所以终止状态的容器:docker container prune

Docker-仓库

目前 Docker 官方维护了一个公共仓库 Docker Hub,其中已经包括了数量超过 15,000 的镜 像。大部分需求都可以通过在 Docker Hub 中直接下载镜像来实现。

登录dockerhub:docker login

查找镜像:docker search

推送镜像:docker push

给镜像打标签:docker tag

保存一个镜像的改变:docker commit

利用dockerfile构建镜像:docker build

Docker-建立私有registry

docker方式运行一个私有registry镜像

docker pull registry docker run --name registry -p 5000:5000 --restart always -d registry

使用私有库 docker pull hello-world docker tag hello-world localhost:5000/hello-world

docker push localhost:5000/hello-world docker pull localhost:5000/hello-world

查找镜像: http://192.168.0.108:5000/v2/_catalog 或者 curl -X GET http://localhost:5000/v2/_catalog

Docker-数据卷

为什么需要数据卷?

这得从 docker 容器的文件系统说起。出于效率等一系列原因,docker 容器的文件系统在宿主机上存在的方式很复杂,

这会带来下面几个问题:

  • 不能在宿主机上很方便地访问容器中的文件。
  • 无法在多个容器之间共享数据。
  • 当容器删除时,容器中产生的数据将丢失。

为了解决这些问题,docker 引入了数据卷(volume) 机制。

数据卷是存在于一个或多个容器中的特定文件或文件夹,这个文件或文件夹以独立于 docker 文件系统的形式存在于宿主机中。

数据卷的最大特定是:其生存周期独立于容器的生存周期

使用数据卷的最佳场景

  • 在多个容器之间共享数据,多个容器可以同时以只读或者读写的方式挂载同一个数据卷,从而共享数据卷中的数据。
  • 当宿主机不能保证一定存在某个目录或一些固定路径的文件时,使用数据卷可以规避这种限制带来的问题。
  • 当你想把容器中的数据存储在宿主机之外的地方时,比如远程主机上或云存储上。
  • 当你需要把容器数据在不同的宿主机之间备份、恢复或迁移时,数据卷是很好的选择















数据卷特点

  • 数据卷可以独立于docker文件系统而存在于宿主机
  • 容器可直接使用其文件
  • 可以在不同容器间共享
  • 写入的数据马上生效,无需保存 
  • 操作数据卷不影响镜像
  • 独立于容器生命周期

docker 专门提供了 volume 子命令来操作数据卷:

create        创建数据卷,docker volume create yvesvolume

inspect      显示数据卷的详细信息

ls               列出所有的数据卷

prune        删除所有未使用的 volumes,并且有 -f 选项

rm             删除一个或多个未使用的 volumes,并且有 -f 选项

 

在这里我们可以看到创建数据卷的时间; 该数据卷使用的驱动程序为默认的 “local”,

表示数据卷使用宿主机的本地存储;数据卷的挂载点,默认是本机 /var/lib/docker/volumes 下的一个目录。我们可以使用 rm 或 prune 命令删除数据卷

使用 mount 语法挂载数据卷1 之前我们使用 --volume(-v) 选项来挂载数据卷,

现在 docker 提供了更强大的 --mount 选项来管理数据卷。

mount 选项可以通过逗号分隔的多个键值对一次提供多个配置项,因此 mount 选项可以提供比 volume 选项更详细的配置。

使用 mount 选项的常用配置如下:type 指定挂载方式,我们这里用到的是 volume,其实还可以有 bind 和 tmpfs。

volume-driver 指定挂载数据卷的驱动程序,默认值是 local。

source 指定挂载的源,对于一个命名的数据卷,这里应该指定这个数据卷的名称。在使用时可以写 source,也可以简写为 src。

destination 指定挂载的数据在容器中的路径。在使用时可以写 destination,也可以简写为 dst 或 target。

readonly 指定挂载的数据为只读

volume-opt 可以指定多次,用来提高更多的 mount 相关的配置

使用 mount driver把数据存储在其他地方

除了默认的把数据卷中的数据存储在宿主机,docker 还允许我们通过指定 volume driver 的方式把数据卷中的数据存储在其它的地方,比如 Azrue Storge 或 AWS 的 S3。

简单起见,我们接下来的 demo 演示如何通过 vieux/sshfs 驱动把数据卷的存储在其它的主机上。

docker 默认是不安装 vieux/sshfs 插件的,我们可以通过下面的命令进行安装:

docker plugin install --grant-all-permissions vieux/sshfs

然后通过 vieux/sshfs 驱动创建数据卷,并指定远程主机的登录用户名、密码和数据存放目录:

docker volume create --driver vieux/sshfs -o sshcmd=nick@10.32.2.134:/home/nick/sshvolume -o password=yourpassword mysshvolume

注意,请确保你指定的远程主机上的挂载点目录是存在的(demo 中是 /home/nick/sshvolume 目录),否则在启动容器时会报错。

最后在启动容器时指定挂载这个数据卷: docker run -id --name testcon --mount type=volume,volume-driver=vieux/sshfs,source=mysshvolume,target=/world ubuntu /bin/bash

这就搞定了,你在容器中 /world 目录下操作的文件都存储在远程主机的 /home/nick/sshvolume 目录中。

进入容器 testcon 然后在 /world 目录中创建一个文件,然后打开远程主机的  /home/nick/sshvolume 目录进行查看,你新建的文件是不是已经出现在那里了

Dockerfile

  • 使用Dockerfile定制镜像
  • 镜像的定制实际上就是定制每一层所 添加的配置、文件;我们可以把每一层修改、安装、构建、操作的命令都写入一个脚 本,用这个脚本来构建、定制镜像,这个脚本就是 Dockerfile。
  • Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层, 因此每一条指令的内容,就是描述该层应当如何构建。
  • 尝试定制一个自己的 nginx 镜像:
  • mkdir dockerfile
  • cd dockerfile
  • touch Dockerfile
  • Dockerfile 的内容: FROM nginx RUN echo 'Hello, Docker!' > /usr/share/nginx/html/index.html 这个 Dockerfile 很简单,一共就两行。涉及到了两条指令, FROM 和 RUN 。

FROM:指定基础镜像 所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。就像我们之前运行了一个 nginx 镜像的容器,再进行修改一样,基础镜像是必须指定的。

而 FROM 就是指定基础镜 像,因此一个 Dockerfile 中 FROM 是必备的指令,并且必须是第一条指令。 在 Docker Store 上有非常多的高质量的官方镜像,有可以直接拿来使用的服务类的镜像,

如 nginx 、 redis 、 mongo 、 mysql 、 httpd 、 php 、 tomcat 等;也有一些方便开发、构 建、运行各种语言应用的镜像,如 node 、 openjdk 、 python 、 ruby 、 golang 等。可以 在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。

如果没有找到对应服务的镜像,官方镜像中还提供了一些更为基础的操作系统镜像,如 ubuntu 、 debian 、 centos 、 fedora 、 alpine 等,这些操作系统的软件库为我们提供了 更广阔的扩展空间。

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

RUN:执行命令 RUN 指令是用来执行命令行命令的。由于命令行的强大能力, RUN 指令在定制镜像时是最 常用的指令之一。

其格式有两种: shell 格式: RUN exec 格式: RUN ["可执行文件", "参数1", "参数2"] 之前说过,Dockerfile 中每一个指令都会建立一层, RUN 也不例外。

每一个 RUN 的行为, 就和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束 后, commit 这一层的修改,构成新的镜像。

规定是镜像的最大层数现在是不得超过 127 层;尽量使用 && 把run命令串联起来。 Dockerfile 支持 Shell 类的行尾添加 的命令换行方 式,以及行首 # 进行注释的格式。

build:构建镜像 docker build -t nginx:v3 

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

Dockerfile 指令详解 我们已经介绍了 FROM , RUN ,其实 Dockerfile 功能很强大,它提 供了十多个指令。

下面我们继续讲解其他的指令。

COPY 复制文件

COPY <源路径>... <目标路径>

COPY ["<源路径1>",... "<目标路径>"]

COPY package.json /usr/src/app/

ADD 更高级的复制文件 ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。 比如 可以是一个 URL

CMD 容器启动命令 CMD 指令的格式和 RUN 相似,也是两种格式:

shell 格式: CMD <命令>

exec 格式:CMD ["可执行文件", "参数1", "参数2"...]

CMD 指令就是用于指定默认的容器主进程的 启动命令的。比如, ubuntu 镜像默认的 CMD 是 /bin/bash ,如果我们直接 docker run -it ubuntu 的话,会直接进入 bash 。

ENV 设置环境变量 格式有两种: ENV <key> <value> ENV <key1>=<value1> <key2>=<value2>... 这个指令很简单,就是设置环境变量而已,无论是后面的其它指令,如 RUN ,还是运行时的 应用,都可以直接使用这里定义的环境变量。

VOLUME 定义匿名卷 之前我们说过,容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存 动态数据的应用,其数据库文件应该保存于卷(volume)中。

在 Dockerfile 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂 载,其应用也可以正常运行,不会向容器存储层写入大量数据。

EXPOSE 声明端口 格式为 EXPOSE <端口1> [<端口2>...] EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声 明应用就会开启这个端口的服务。

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

原文地址:https://www.cnblogs.com/yjjyves/p/9752648.html