06-Docker

⼀. Docker介绍

Docker是什么?

Docker 是⼀个开源的应⽤容器引擎,基于Go语⾔并遵从Apache2.0协议开源。
Docker 可以让开发者打包他们的应⽤以及依赖包到⼀个轻量级、可移植的容器中,然后发布到任何
流⾏的Linux机器上,也可以实现虚拟化。
容器是完全使⽤沙箱机制,相互之间不会有任何接⼝(类似 iPhone 的 app),更重要的是容器性能
开销极低。

容器和虚拟机

虚拟机:
虚拟机如VMware,VisualBox之类的需要模拟整台机器包括硬件,每台虚拟机都需要有⾃⼰的
操作系统,虚拟机⼀旦被开启,预分配给它的资源将全部被占⽤。每⼀台虚拟机包括应⽤,必要的⼆进
制和库,以及⼀个完整的⽤户操作系统。

容器:
容器技术是和我们的宿主机共享硬件资源及操作系统,可以实现资源的动态分配。容器包含应⽤
和其所有的依赖包,但是与其他容器共享内核。容器在宿主机操作系统中,在⽤户空间以分离的进程运
⾏。
Docker属于Linux容器的⼀种封装,提供简单易⽤的容器使⽤接⼝。它是⽬前最流⾏的Linux容器解
决⽅案。

Docker的优势
Docker相⽐于传统虚拟化⽅式具有更多的优势:
  1. docker启动快速属于秒级别。虚拟机通常需要⼏分钟去启动.
  2. docker需要的资源更少,docker在操作系统级别进⾏虚拟化,docker容器和内核交互,⼏乎没有性能损耗,性能优于通过 Hypervisor 层与内核层的虚拟化
  3. docker 更轻量, docker 的架构可以共⽤⼀个内核与共享应⽤程序库,所占内存极⼩。同样的硬件环境, Docker 运⾏的镜像数远多于虚拟机数量,对系统的利⽤率⾮常⾼
  4. 与虚拟机相⽐,docker隔离性更弱,docker属于进程之间的隔离,虚拟机可实现系统级别隔离
  5. 安全性: docker的安全性也更弱。 Docker 的租户 root 和宿主机 root 等同,⼀旦容器内的⽤户从普通⽤户权限提升为root权限,它就直接具备了宿主机的root权限,进⽽可进⾏⽆限制的操作。虚拟机租户 root 权限和宿主机的 root 虚拟机权限是分离的,并且虚拟机利⽤如 Intel 的VT-d 和 VT-x 的 ring-1 硬件隔离技术,这种隔离技术可以防⽌虚拟机突破和彼此交互,⽽容器⾄今还没有任何形式的硬件隔离,这使得容器容易受到攻击
  6. 可管理性:docker的集中化管理⼯具还不算成熟。各种虚拟化技术都有成熟的管理⼯具,例如VMware vCenter 提供完备的虚拟机管理能⼒
  7. ⾼可⽤和可恢复性: docker 对业务的⾼可⽤⽀持是通过快速重新部署实现的。虚拟化具备负载均衡,⾼可⽤,容错,迁移和数据保护等经过⽣产实践检验的成熟保障机制, VMware 可承诺虚拟机99.999% ⾼可⽤,保证业务连续性
  8. 快速创建、删除:虚拟化创建是分钟级别的, Docker 容器创建是秒级别的, Docker 的快速迭代性,决定了⽆论是开发、测试、部署都可以节约⼤量时间
  9. 交付、部署:虚拟机可以通过镜像实现环境交付的⼀致性,但镜像分发⽆法体系化。 Docker 在Dockerfile 中记录了容器构建过程,可在集群中实现快速分发和快速部署


    比较.png
Docker的三个基本概念

Image(镜像)
Container(容器)
Repository(仓库)
镜像是 Docker 运⾏容器的前提,仓库是存放镜像的场所,可⻅镜像更是 Docker 的核⼼。

Image (镜像)

Docker镜像:
可以看作是⼀个特殊的⽂件系统,除了提供容器运⾏时所需的程序、库、资源、配置等⽂件外,还包含了⼀些为运⾏时准备的⼀些配置参数(如匿名卷、环境变量、⽤户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
镜像是只读的,镜像中包含有需要运⾏的⽂件。镜像⽤来创建container,⼀个镜像可以运⾏多个container;镜像可以通过Dockerfile创建,也可以从Docker hub/registry上下载。

Container (容器)

容器 (container) 的定义和镜像 (image) ⼏乎⼀模⼀样;
容器⼀般要由镜像来创建, ⼀个镜像可以创建任意多个相同的容器;
容器是Docker的运⾏组件,启动⼀个镜像就是⼀个容器,容器是⼀个隔离环境,多个容器之间不会相互影响,保证容器中的程序运⾏在⼀个相对安全的环境中。

Repository (仓库)

Docker仓库是集中存放镜像⽂件的场所。镜像构建完成后,可以很容易的在当前宿主上运⾏,但是,如果需要在其它服务器上使⽤这个镜像,我们就需要⼀个集中的存储、分发镜像的服务,DockerRegistry (仓库注册服务器)就是这样的服务。有时候会把仓库 (Repository) 和仓库注册服务器(Registry) 混为⼀谈,并不严格区分。Docker 仓库的概念跟 Git 类似,注册服务器可以理解为GitHub 这样的托管服务。实际上,⼀个 Docker Registry 中可以包含多个仓库(Repository) ,每个仓库可以包含多个标签 (Tag),每个标签对应着⼀个镜像。所以说,镜像仓库是 Docker ⽤来集中存放镜像⽂件的地⽅类似于我们之前常⽤的代码仓库。
通常,⼀个仓库会包含同⼀个软件不同版本的镜像,⽽标签就常⽤于对应该软件的各个版本。我们可以通过<仓库名>:<标签>的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以latest作为默认签.。
仓库⼜可以分为两种形式:
public(公有仓库)
private(私有仓库)
Docker Registry 公有仓库是开放给⽤户使⽤、允许⽤户管理镜像的 Registry 服务。⼀般这类公开服务允许⽤户免费上传、下载公开的镜像,并可能提供收费服务供⽤户管理私有镜像。
除了使⽤公开服务外,⽤户还可以在本地搭建私有 Docker Registry 。Docker 官⽅提供了Docker Registry 镜像,可以直接使⽤做为私有 Registry 服务。当⽤户创建了⾃⼰的镜像之后就可以使⽤ push 命令将它上传到公有或者私有仓库,这样下次在另外⼀台机器上使⽤这个镜像时候,只需要从仓库上 pull 下来就可以了。
https://hub.docker.com/

⼆. Docker安装

  • 由于apt官方库里的docker版本可能比较旧,所以先卸载可能存在的旧版本:
$ sudo apt-get remove docker docker-engine docker-ce docker.io
  • 更新apt包索引:
$ sudo apt-get update
  • 安装以下包以使apt可以通过HTTPS使用存储库(repository):
$ sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
  • 添加Docker官方的GPG密钥:
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
  • 使用下面的命令来设置stable存储库:
$ sudo add-apt-repository "[deb](https://www.baidu.com/s?wd=deb&tn=24004469_oem_dg) [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
  • 再更新一下apt包索引:
$ sudo apt-get update
  • 安装最新版本的Docker CE:
$ sudo apt-get install -y docker-ce
  • 在生产系统上,可能会需要应该安装一个特定版本的Docker CE,而不是总是使用最新版本:
$ apt-cache madison docker-ce
版本.png

选择要安装的特定版本,第二列是版本字符串,第三列是存储库名称,它指示包来自哪个存储库,以及扩展它的稳定性级别。要安装一个特定的版本,将版本字符串附加到包名中,并通过等号(=)分隔它们:

$ sudo apt-get install docker-ce='版本号'
验证docker
  • 查看docker服务是否启动:
$ systemctl status docker
  • 若未启动,则启动docker服务:
$ sudo systemctl start docker
  • 经典的hello world:
$ sudo docker run hello-world
hello world.png

有以上输出则证明docker已安装成功!

三. 镜像加速

鉴于国内⽹络问题,后续拉取 Docker 镜像⼗分缓慢,我们可以需要配置加速器来解决,我使⽤的是⽹易的镜像地址:http://hub-mirror.c.163.com
新版的 Docker 使⽤ /etc/docker/daemon.json(Linux) 或者%programdata%\docker\config\daemon.json(Windows) 来配置 Daemon。
请在该配置⽂件中加⼊(没有该⽂件的话,请先建⼀个):

$ vim /etc/docker/daemon.json

{
"registry-mirrors": ["http://hub-mirror.c.163.com"]
}

四. 开始使⽤Docker

使⽤ docker run 命令来在容器内运⾏⼀个应⽤程序。

$ sudo docker run ubuntu /bin/echo "Hello world"
$ docker run -i -t ubuntu /bin/bash
[docker run -it ubuntu /bin/bash]
• -t: 在新容器内指定⼀个伪终端或终端。
• -i: 允许你对容器内的标准输⼊ (STDIN) 进⾏交互。
• /bin/bash: 进⼊容器
exit: 退出容器

五. Docker容器

  • 拉取镜像
$ sudo docker pull training/webapp 
  • 使⽤镜像创建容器
$ sudo docker run -d -P training/webapp python app.py
• -d: 让容器在后台运⾏。
• -P: 将容器内部使⽤的⽹络端⼝映射到我们使⽤的主机上。
  • 查看正在运⾏的容器
$ sudo docker ps
$ sudo docker ps -l #查询最后⼀次创建的容器

通过 -p 参数来设置不⼀样的端⼝:

$ sudo docker run -d -p 5000:5000 training/webapp python app.py

也可以指定容器绑定的⽹络地址:

$ sudo docker run -d -p 127.0.0.1:5001:5000 training/webapp python app.py
  • 停⽌容器
$ sudo docker stop container_id 
  • 重启容器
$ sudo docker start container_id
  • 删除容器: 删除容器时,容器必须是停⽌状态,否则会报错误
$ sudo docker rm container_id
# 删除所有容器
$ sudo docker rm `docker ps -a -q` 

六. Docker镜像

  • 查看镜像列表
$ sudo docker images

REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 16.04 80d0abcdeaf 1 days ago 100 M
• REPOSITORY:表示镜像的仓库源
• TAG:镜像的标签
• IMAGE ID:镜像ID
• CREATED:镜像创建时间
• SIZE:镜像⼤⼩
• 同⼀仓库源可以有多个 TAG,代表这个仓库源的不同个版本

$ sudo docker search ubuntu
  • 获取镜像
$ sudo docker pull ubuntu
  • 删除镜像
$ sudo docker rmi image_id
# 删除所有镜像
$ sudo docker rmi `docker images -q` 
Dockerfile
  • 构建镜像: 通过创建⼀个 Dockerfile ⽂件来创建镜像
$ sudo cat Dockerfile

Dockerfile⽂件内容格式:

FROM python:3.7
MAINTAINER niejeff 123456@qq.com
RUN /bin/echo "hello"
EXPOSE 80
CMD /usr/sbin/sshd -D
每⼀个指令都会在镜像上创建⼀个新的层,每⼀个指令的前缀都必须是⼤写的。
FROM: 指定基础镜像
MAINTAINER: ⽤于指定镜像创建者和联系⽅式
RUN: 容器内部的执⾏Linux命令
EXPOSE: ⽤来指定对外开放的端⼝
CMD: ⽤于启动容器时默认执⾏的命令

写个例⼦来构建Dockerfile

mkdir static_web
cd static_web
vim Dockerfile 

Dockerfile内容

FROM python:3.7
MAINTAINER niejeff 123456@qq.com

在Dockerfile所在⽬录执⾏:

$ sudo docker build -t docker_demo/flask_web:v1 .
-t 是为新镜像设置仓库和名称
docker_demo 为仓库名
nginx_web 为镜像名
:v1 为标签(不添加为默认 latest )

构建完成之后,再查看所有镜像

$ sudo docker images

将镜像上传到hub.docker仓库

$ sudo docker login
先tag, 再push
docker tag local-image:tagname reponame:tagname
docker push reponame:tagname
例如
docker tag docker_demo/flask_web:v1 niejeff/docker_demo
• docker_demo/flask_web:v1 : 镜像REPOSITORY:TAG
• niejeff/docker_demo : ⽤户名/仓库名
docker push niejeff/docker_demo

七. ⽤Docker部署Flask应⽤

创建Flask应⽤

先创建⽂件夹myflask 在myflask中创建app.py, 内容如下

from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
 return 'hello flask'
if __name__ == '__main__':
 app.run(debug=True)
使⽤Gunicorn+Gevent运⾏Flask应⽤

进⼊虚拟环境, 安装包

$ pip install gunicorn gevent

在myflask⽂件夹下编写gunicorn的配置⽂件gunicorn.conf.py

workers = 8 # 进程数量
worker_class = "gevent" # 采⽤gevent库,⽀持异步处理请求,提⾼吞吐量
bind = "0.0.0.0:8888" # 监听IP放宽,以便于Docker之间、Docker和宿主机之间的通信

使⽤gunicorn命令进⾏测试

$ gunicorn app:app -c gunicorn.conf.py

打开浏览器,输⼊ 127.0.0.1:8888 ,可以看到返回的⽹⻚中展示内容 hello flask。

改⽤Docker运⾏Flask应⽤

在myflask⽂件夹下创建⽂件requirements.txt

flask
gunicorn
gevent

创建Dockerfile来构造镜像

FROM python:3.5
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["gunicorn", "app:app", "-c", "./gunicorn.conf.py"]

开始构造镜像

$ sudo docker build -t 'myflask' .

查看该镜像是否已经创建

$ sudo docker images

运⾏docker镜像

$ sudo docker run -it --rm -p 8888:8888 myflask
--rm : 容器运⾏结束时会⾃动删除该容器

最后打开浏览器,输⼊ 127.0.0.1:8888 ,可以看到返回的⽹⻚中展示内容 hello flask
如果是在云服务器端运⾏的Docker容器, 则输⼊: 公⽹IP:8888来访问

推荐阅读更多精彩内容

  • 一、Docker 简介 Docker 两个主要部件:Docker: 开源的容器虚拟化平台Docker Hub: 用...
    R_X阅读 3,719评论 0 27
  • 一定要经常走出去,多看看优秀的人,辽阔的世界,视野和见识扩大了,人心也大了
    凡尘花韵阅读 54评论 0 0
  • 1. 2016年4月份接到日本出差项目的时候,我几乎是没有犹豫就接受了。家人,朋友,同事都表示担心,试图劝说,但是...
    美滋滋tu阅读 356评论 0 0
  • 是不是俗的不能再俗的题目,然而真的是随手画的一笔。 坐在电脑前,看着时钟一分分的走过,明明知道已经到了惯常休息的时...
    小小鹿乱撞阅读 82评论 0 1