获取 Docker
Docker 有两个可用的版本,社区版:ommunity Edition (CE), 企业版:Enterprise Edition (EE),Docker Community Edition(CE)非常适合希望开始使用Docker并尝试使用基于容器的应用程序的开发人员和小型团队,社区版有两个主要的更新通道,stage, edge:
- stage: 每个季度更新一次,稳定可靠
- edge: 每月更新一次,能够体验最新的功能
Docker企业版(EE)专为企业级开发人员和IT团队而设计,他们在大规模生产中构建,发布和运行关键业务应用程序.
安装 Docker
针对 Mac 安装 CE 版本
其他的版本可以参考官方文档
Homebrew的Cask已经支持docker for Mac,因此可以使用Homebrew Cask 来进行安装:
1
brew cask install docker
启动终端,查看docker是否安装成功:
1
2
3
4
5
6➜ ~ docker --version
Docker version 17.12.0-ce, build c97c6d6
➜ ~ docker-machine --version
docker-machine version 0.13.0, build 9ba6da9
➜ ~ docker-compose --version
docker-compose version 1.18.0, build 8dd22a9如果docker version,docker info 都运行正确的话,可以尝试启动一个nginx试试:
1
docker run -d -p 8090:80 --name webserver nginx
一切正常的话,打开浏览器,输入:http://localhost:8090你将看到:
列出你创建的容器:
1
docker ps -a
停止启动的容器:
1
docker stop xxxx
删除你创建的容器:
1
docker rm xxxxxx
查看已经下载的镜像:
1
docker images
除此之外,一些常用的命令如下:
docker命令 意义 docker version 查看docker版本 docker search xxx 从仓库中查找镜像 docker pull xxx/xxx(用户名/镜像名) 从仓库中下载镜像 docker run xxx/xxx(用户名/镜像名) 启动容器 docker ps (-l , -a…) 查看所有容器 docker inspect 容器id 查看具体容器 docker commit 容器id 从容器创建一个新的镜像 docker push xxx/xxx(用户名/镜像名) 提交镜像 docker port 容器名 查看容器的端口映射情况
镜像服务(加速器)
- 我们常用的Registry是docker官方的Docker Hub,这也是默认的 Registry,并拥有大量的高质量的官方镜像。还有quay.io。由于某些原因,在国内访问这些服务可能会比较慢。国内的一些云服务商提供了针对 Docker Hub 的镜像服务(Registry Mirror),这些镜像服务被称为加速器。常见的有:阿里云加速器,DaoCloud加速器;
使用Docker
容器的简要说明
镜像(image)是一个轻量级的,独立的可执行程序包,包含运行一个软件所需的所有东西,包括代码运行时依赖库,环境变量和配置文件。
容器是镜像的运行时示例,镜像运行时在内存中变成的内容,默认情况下,它与主机完全隔离,只有在配置的情况下才可访问主机的端口和文件。
容器在系统内核上就地运行应用程序,同通过管理程序获得一个接入主机资源的虚拟机相比,他有更好的性能特点,容器可以获得本地访问权限,每个容器都以独立的进程运行,相比其他的应用程序,不需要更多的内存。
虚拟机 VS 容器
虚拟机通过中间层将一台或者多台独立的及其运行于物理硬件当中;而容器则是直接运行在操作系统内核之上的用户空间
容器技术的磁盘占有空间少,虚拟机部署应用包含应用和其依赖的库,还需要包含完整的操作系统,容器只需前两者。另外,虚拟机需要模拟硬件的行为,对cpu,内存消耗较大
虚拟机运行原理:
虚拟机运行客户操作系统, 注意在每个box中都有一个系统层。这是资源密集型,这将导致磁盘镜像,应用程序状态同系统设置,系统安装的依赖以及系统补丁纠缠在一起,而且容易丢失,很难复制。传统虚拟机技术就是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;
容器运行原理:
容器可以共享一个内核,并且唯一需要在容器镜像中的信息是可执行文件及其包依赖关系,它们永远不需要安装在主机系统上。这些进程的运行就如同本地的进程一样,你可以使用docker ps命令管理他们,就像你在linux平台使用ps命令查看本地进程一样,最后,因为他们包含了所有的依赖关系,就没有配置依赖的纠葛。一个集装箱化的应用程序可以随处运行。
构建并运行你的第一个应用程序
Introduction
现在是时候用docker的方式构建一个应用程序了,我们将从这个应用程序的底部开始构建,这个应用程序是一个容器,然后我们再在这一层上添加新的东西。在这个层次上面是一个服务,它定义了容器在生产环境中的行为,这个将在接下里的一节中讲到。最后在顶层是stacks,定义所有服务的交互,将在第五部分讲到。结构层次大概是这样式的:
stacks
Services
containers(我们现在在这里)
Your new development environment
过去,你写一个PythonAPP的时候,流程的第一步就是在你的电脑上安装Python运行库。但是这将造成这样的情况,不仅需要一个能完美运行应用程序的本地环境,同时还需要一个与之匹配的生产环境。
使用docker,你可以将一个基础的可移植的Python运行环境作为一个镜像,然后你的构建将包括Python基础的镜像和你的应用程序代码,确保你的应用程序,它的依赖和运行时都是在一起的。
这些可移植的镜像可以由一个叫做Dockerfile的文件来进行定义。
Dockerfile
- 接下来要跟着一起来动手了,只有在动手的过程中才能体会到生命的乐趣。创建一个新的目录,并且切换到新的目录下创建一个文件:Dockerfile,复制粘贴下面的内容然后保存,可以看看里面的解释。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20# 使用一个官方的Python运行时作为基础
FROM python:3.6-slim
# 设置工作目录为/app
WORKDIR /app
# 复制当前目录的内容到/app
ADD . /app
# 安装requirements.txt中声明包
RUN pip install --trusted-host mirrors.aliyun.com --index http://mirrors.aliyun.com/pypi/simple/ -r requirements.txt
# 暴露端口80给容器外部的环境
EXPOSE 80
# 定义一个环境变量
ENV NAME World
# 当容器启动的时候运行app.py
CMD ["python", "app.py"] - Dockerfile中涉及到几个文件我们还没有创建,app.py以及requirements.txt。
应用程序
- 我们在Dockerfile所在的目录下再创建两个文件:app.py以及requirements.txt,文件内容如下所述,这就算是补全我们的应用程序,虽说简单,但是五脏俱全。
- requirements.txt
1
2Flask
Redis
-app.py
1 | from flask import Flask |
- 现在我们将看到pip install -r requirements.txt安装了flask和redis的Python扩展,应用将打印环境变量NAME以及socker.gethostname()的输出,但是由于我们没有安装redis服务,所以我们期望这里打印错误信息。
build app
现在我们构建我们的APP,在开始构建的使我们,在我们的应用目录下执行ls,应该至少看到以下这几个文件:Dockerfile, requirements.txt, app.py
现在我们执行构建命令,这将创建一个新的镜像,我们也使用-t创建一个友好的标签。
1
docker build -t firstapp .
构建的镜像在哪里?可以使用docker images 查看
1
docker images
Run the app
- 运行容器的时候,我们将使用-p参数将主机的4040端口映射到容器的80端口:
1 | docker run -p 4040:80 firstapp |
启动成功的时候你将看到一个来自容器内部的消息:* Running on http://0.0.0.0:80/ (Press CTRL+C to quit), 因为容器并不知道我们将80端口映射到了4040,所以在浏览器中输入以下URL进行访问:http://localhost:4040,我们将看到以下的结果:
使用CTRL+C进行退出
或者我们可以让容器在后台启动:
1
docker run -d -p 4040:80 firstapp
share your image
为了验证可移植性,我们将刚刚创建的镜像上传然后在其他地方运行。毕竟你需要知道当部署应用到生产环境的时候如何推送镜像到registry。一个registry是一系列的集合,一个仓库是一系列镜像的集合。一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。
通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。
以 Ubuntu 镜像 为例,ubuntu 是仓库的名字,其内包含有不同的版本标签,如,14.04, 16.04。我们可以通过 ubuntu:14.04,或者 ubuntu:16.04 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 ubuntu,那将视为 ubuntu:latest。
仓库名经常以 两段式路径 形式出现,比如 jwilder/nginx-proxy,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。
执行命令docker login使用dockerID进行登录。
执行命令docker tag image username/repository:tag 给镜像打标签,例如:docker tag firstapp gamelife1314/firstapp:0.1
执行命令docker push gamelife1314/firstapp:0.1发布镜像;
发布成功之后我们可以使用docker run -p 4040:80 gamelife1314/firstapp:0.1在任何机器上运行我们的应用程序了。
Services
在这部分中,我们扩展了应用程序并实现了负载平衡。要做到这一点,我们必须在分布式应用程序的层次结构中上一级:服务。
在分布式应用程序中,应用程序的不同部分被称为“服务”。例如,如果您想象一个视频共享站点,它可能包括一个用于将应用程序数据存储在数据库中的服务,后台运行的转码服务,一个用于前端的服务等等。
服务实际上只是“生产中的容器”。服务只运行一个镜像,但它定义了镜像运行的方式 - 应该使用哪个端口,容器应该运行多少个副本以便达到所需的容量,以及等等。Scaling a service changes the number of container instances running that piece of software, assigning more computing resources to the service in the process(扩展一个服务会改变运行该软件的容器实例的数量,已分配给程序中的服务更多的计算资源).
第一个docker-compose.yaml文件格式
docker-compose.yaml是一个YAML格式的文件,描述了生产环境中docker的行为方式。
docker-compose.yaml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19version: "3"
services:
web:
# 使用前一节创建的镜像
image: gamelife1314/firstapp:0.1
deploy:
replicas: 5
resources:
limits:
cpus: "0.1"
memory: 50M
restart_policy:
condition: on-failure
ports:
- "4040:80"
networks:
- webnet
networks:
webnet:这个docker-compose.yaml 告诉docker做以下的事情:
- 从registry中拉取创建的镜像;
- 运行镜像的5个实例作为一个服务叫做web,限制每一个实例使用资源的上限 10% of the CPU (across all cores), 以及 50MB of RAM.
- 如果有一个失败,立即重启容器;
- 映射主机的4040端口到容器的80端口;
- 指示web容器通过叫做webnet的负载均衡网络共享端口80;
- 使用默认设置定义webnet网络;
然后运行:docker stack deploy -c docker-compose.yaml firstapp firstapp是应用程序名称;
我们单个service stack 在一个主机上运行了镜像的5个实例,可以通过docker srevice ls查看我们应用的服务id;
Docker 概述
- docker 基于linux内核,是一种容器技术(容器虚拟化的方案)
- docker 是一个可以把开发的应用程序自动的部署到容器中的一个开源引擎(Golang)
- docker 在虚拟化的容器执行环境中,增加了一个应用程序部署引擎
- CS架构。docker客户端和docker的守护进程进行通信。Docker守护进程负责构建,运行和分发Docker容器。docker客户端可以运行在同一个机器上,但是docker客户端也可以连接远端的docker服务。docker客户端和docker守护进程的交互通过一个restfulAPI,或者Unix socket,或者一盒网络接口。
docker组成
- Docker Client 客户端
- Docker Daemon 守护进程
- Docker Image 镜像
- Docker Container 容器
- Docker Registry 仓库
Docker Client / Docker Daemon (c/s架构)
- 终端中的一些docker命令(eg : docker pull, docker run …)通过client传给daemon(支持远程),然后返回结果
- 通过客户端访问守护进程,进而操作容器
Docker Image
- 容器的基石,容器基于镜像启动和运行
- 一个镜像可以作为另外镜像的底层镜像(父镜像)
Docker Container
- 通过镜像启动,是docker的执行单元,一个container可以运行一个/多个用户进程
Docker Registry
- 用户保存用户的镜像,分为public和private
- docker 官方提供公开的仓库 Docker Hub
Docker registries
- docker registry 用于存储docker镜像。docker hub 和 docker cloud 是公共的 registry,任何人都可以使用。docker默认从docker hub 获取镜像。当然你也可以使用自己的registry。
Docker 容器的基本操作
交互式容器
docker run IMAGE [COMMAND] [ARG…]
在新的容器中执行命令
docker run -i -t IMAGE /bin/bash
- eg : docker run -i -t ubuntu /bin/bash
- -i : –interactive = true (打开标准输入)
- -t : –tty = true (打开tty终端)
- eg : docker run -i -t ubuntu /bin/bash
自定义容器名称 : docker run –name=自定义名字 -i -t IMAGE /bin/bash
docker start [-i] 容器名
- 重新启动容器(不产生新的容器)
docker rm 容器名
- 删除已经停止的容器
守护式容器
docker run -d IMAGE [COMMAND] [ARG…]
- -d : 后台方式运行
docker attach 容器名
- 附加到运行中的容器
docker logs [-f][-t][–tail] 容器名
- -f : –follows=true : 追踪日志
- -t : – timestamps=true : 日志加上时间戳
- –tail=”all” : tail 的意思是返回结尾出多少数量的日志,如果不指定,返回所有
docker top 容器名
- 查看运行中容器内所有的进程
- docker exec -d [-d][-i][-t] 容器名 [COMMAND] [ARG…]
- 在容器内启动新的进程
docker stop 容器名
- 向容器发送信号,等待容器停止
docker kill 容器名
- 直接停止容器
容器中的部署
- 容器的端口映射
- run [-P][-p] (大小写)
- -P : –publish-all=true 为容器所有暴露的端口进行映射
- eg : docker run -P -i -t ubuntu /bin/bash
- -p : –publish=[] 指定映射容器的哪些端口, 有多种格式
- 只指定容器的端口 (containerPort)
- 宿主机的端口随机映射
- eg : docker run -p 80 -i -t ubuntu /bin/bash
- 同时指定宿主机和容器端口 (hostPort : containerPort)
- 一一对应的
- eg : docker run -p 80 -i -t ubuntu /bin/bash
- ip对应容器端口 (ip : containerPort)
- eg : docker run -p 0.0.0.0:80 -i -t ubuntu /bin/bash
- ip+端口对应容器端口 (ip+port : containerPort)
- eg : docker run -p 0.0.0.0:8080:80 -i -t ubuntu /bin/bash
- 只指定容器的端口 (containerPort)
- -P : –publish-all=true 为容器所有暴露的端口进行映射
- run [-P][-p] (大小写)
对镜像的操作
镜像的两个重要属性
- repository 镜像的仓库, eg : ubuntu, centos …
- tag 标签
列出镜像
- docker images [OPTSIONS] [REPOSITORY]
- -a 查看所有的镜像
- -f, –filter=[] 添加过滤条件
- -q 只查看镜像的唯一id
- docker images [OPTSIONS] [REPOSITORY]
查看镜像的具体信息
- docker inspect [OPTIONS] CONTAINER/IMAGE (这个命令既支持容器的查看,也支持镜像的查看)
- -f : –format=””
- docker inspect [OPTIONS] CONTAINER/IMAGE (这个命令既支持容器的查看,也支持镜像的查看)
删除镜像
- docker rmi [OPTIONS] IMAGE
- -f 强制删除
- 删除所有镜像 : docker rmi $(docekr images -q)
- docker rmi [OPTIONS] IMAGE
查找镜像
- docker search [OPTIONS] TERM
拉取镜像
- docker pull [OPTIONS] NAME[:TAG]
- -a 下载所有匹配NAME的有tag的
- docker pull [OPTIONS] NAME[:TAG]
推送镜像
- docker push NAME[:TAG]
Dockerflie
FROM
- FROM [image]:[tag]
- dockerfile第一条非注释的指令
MAINTAINER
- 作者信息,一般包含所有者以及联系方式
RUN
镜像构建过程中的指令,包含当前镜像中运行的命令,包含两种模式(shell & exec)
RUN [command] (shell 模式)
- 以 /bin/bash -c command 执行命令
- eg : RUN echo hello
- 以 /bin/bash -c command 执行命令
RUN [“executable”, “param1”, “param2”] (exec 模式)
可以指定其他形式的shell来运行指令
- eg : RUN [“/bin/bash”, “-c”, “echo hello”]
EXPOSE
- 指定暴露的容器的端口
CMD
- 容器运行的默认命令,与前面的RUN不同的是 : 后者是构建镜像的过程中执行的命令
- 如果在使用
docker run
命令运行容器的时候加上了容器运行时候的指令,则cmd中的指令会被覆盖,不会执行。既:cmd用于指定容器的默认行为 - CMD指令的两种模式(shell & exec & 特殊模式)
- CMD command param1 param2 (shell 模式)
- 以 /bin/bash -c command 执行命令
- eg : CMD echo hello
- 以 /bin/bash -c command 执行命令
- CMD [“executable”, “param1”, “param2”] (exec 模式)
- 可以指定其他形式的shell来运行指令
- eg : CMD [“/bin/bash”, “-c”, “echo hello”]
- CMD [“param1”, “param2”] (只有一些参数)
- 通常与
ENTERYPOINT
指令配合使用,作为其默认参数
- 通常与
ENTERYPOINT
- 与CMD指令类似,也有两种模式(shell & exec),但是它不会被
docker run
指令中的指令覆盖 - 如果需要覆盖,需要在
docker run
指令中加上--enterypoint
选项
- 与CMD指令类似,也有两种模式(shell & exec),但是它不会被
ADD & COPY
- 将文件/目录复制到使用dockerfile构建的镜像中
- 用法 : ADD[COPY] [src]…[dest]
- src : 可以是本地地址(必须是构建目录的相对地址),也可以是url(不推荐用)
- dest : 镜像中的绝对路径
- 区别:
- ADD 包含类似tar的解压功能,如果只是单纯的复制文件,推荐使用COPY
VOLUME
- 用于向基于镜像创建的容器添加卷,可以提供例如共享数据/数据持久化的功能
WORKDIR
- 在使用镜像创建容器时,在容器内部设置工作目录,ENTRYPOINT & CMD 的命令都会在这个目录下执行
- 通常使用绝对路径
ENV
- 设置环境变量,与WORKDIR类似,构建 & 运行 过程中都有效
USER
- 指定镜像以什么样的用户去运行
- 默认使用root用户
ONBUILD
- 为镜像添加触发器,当这个镜像被当作基础镜像的时候,这个指令就会被执行,这个镜像被构建时,会添加触发器中的指令
Docker 数据卷
容器的数据卷
- 什么是数据卷(Data Volume)
- 数据卷设计的目的之一就是在于数据的永久化,既数据卷的生命周期与容器的生命周期独立,既Docker不会在容器删除的时候删除其挂载的数据卷
- docker 数据卷是一个特殊设计的目录,可以绕过联合文件目录(UFS),为一个/多个容器提供访问