微信号:hackerline

介绍:精选Hacker News内容.

Docker浅析——如何从Vagrant转向Docker

2016-08-11 07:38 钟最龙 译

译者介绍:钟最龙,麦芽糖Golang工程师。

Docker是新一代的虚拟化技术,如今大概有三年的历史了。较之以前,它能让构建技术栈复杂的软件更加容易,且隔离性更好。我说的以前,指的是Vagrant、Chef、Puppet等。这些技术的套路都是创建一个基础镜像(包含操作系统和一些基本的软件),并且使用脚本来安装需要的软件或者配置。最后得到一个完整镜像,然后可以轻易地生成快照并且稳定地用于部署了,或者我当时是这么认为的。

背景故事

我们在工作中一直使用PuPHPet(译者注:一个可以配置虚拟机的GUI,可以生成Vagrant的Web开发环境,主要使用Puppet来作为配置后端),到现在至少已经有一年了。PuPHPet用的是YAML格式的配置文件,有很多中间件脚本来构建虚机(machine)。对虚机做改动需要更改YAML配置文件,然后重新执行vagrant provision命令。最初我们感觉像找到了天堂,因为没有它我们需要编写很多些糟心的bash/puppet脚本。而当初它唯一的不足之处只是项目需要提交巨量的文件;不过这是一桩挺公平的买卖。

随着时间推移,PuPHPet自己也在快速的更新。YAML配置文件的格式也变了,最初使用的不同软件包组合也不再支持了,也没有谁给点合理的理由,除了项目想向前推进,只想关注最新的软件包。最无法接受的下边的子系统,Puppet和Ruby的依赖也在不断的变化。这意味着新来的一个开发者,想要构建一个月前还正常的虚机的时候,几乎总是崩溃的。

因此,在一年的时间里,我们不得不很多次完整地对基础配置进行完全重建,而每一次总会给团队带来很大的波动。最后,操作系统(CentOS类的Linux)和PHP(我们依赖版本是PHP 5.4)的结合不工作了,因为默认的(PHP)软件仓库已经不在了。

够了就是够了,我们需要一些更加稳定的东西。

Docker介绍

Docker文档太烂了,这是我见过的最烂的文档之一。对我来说,看了之后我更加糊涂。它编写的时候是假定你已经非常熟悉基于容器的基础设施,并且什么也都不解释一下,或者没有任何你想要寻求的东西。

我想重点介绍一些“明摆着的”的事情,一旦解释清了就很容易理解,但是如果你没有花时间反复尝试却难以理解。希望这能帮助你更顺利的向Docker迁移或者理解Docker。

1. 容器(Container)

Docker使用一种与众不同的虚拟化技术,被称之为容器。一个容器可以被想象成一个完全自包含的机器(machine),为了各种想法或者目标它有自己的操作系统,自己的文件系统,或者任何其他你期待在一个虚拟机器上拥有的东西。但是有一点很重要的是,容器只运行一个程序(注:一个容器实际上可以运行多个进程。然而,正常情况下,不会这么做,除非有特别的原因。在几乎所有的场景中,最好在一个容器中只运行一个进程或者服务。)。例如你可能在一个容器中运行一个MySQL服务,然后在另外一个的容器中运行Redis服务。

即使每个容器的运行基于一个自包含的操作系统,但是他并不像一个专用虚拟操作系统那样需要那么多资源。很多容器可以和主机分享物理资源(像CPU和内存)。

参考链接:

Docker的命令行使用文档(https://docs.docker.com/engine/reference/commandline/cli/)

2. 镜像(Image)

镜像是文件系统的一个快照,然而它们总是基于另外一个镜像。例如,如果我们拿到了一个容器的镜像,它的大小是200MB,然后安装了10MB大小的软件,并生成了另外一个镜像,这个镜像的大小只有10MB,因为它只包含在上一个镜像的基础上所做的更改。

镜像不包含内核,所以通常能看到一些只有几兆大小的镜像。

镜像会被缓存,这可以让容器重新构建非常非常的快。

参考链接:

探索官方的仓库(https://hub.docker.com/explore/)

3. 无状态(Stateless)

每个容器都可能有来自主机挂载到容器里的目录。例如你如果你运行了一个Apache的Web服务器容器,你可能不想将要服务的源文件都塞到容器里面去。相反,你会将一个主机上的目录(其中包含web服务器要服务的文件)挂载到容器中的一个目录,比如:

/Users/elliot/Development/mywebsite` -> `/var/www/html

这样容器(和镜像)就是无状态的了。容器重启或者镜像删除都不会影响应用。这同时让镜像体积更小,重用性更高。另外一个好处是很多容器能共享一个挂载的目录。例如,如果你有多个的web服务器对外提供相同的文件。

4. Dockerfile

Dockerfile是一个纯文本文件,通常位于项目根目录下面。其中包含构建镜像的步骤。这与通常用来安装软件或者设置环境变量的bash脚本类似。一个Dockerfile可能像下面这样:

FROM php:7.0-apache
COPY config/php.ini /usr/local/etc/php/
ENV APP_ENV dev

每一行都是一个命令(command)。第一行总是一个FROM命令,来指定基于什么基础镜像来进行构建。每一步都会创建一个新的镜像,但是每一个镜像只会包含基于上一个快照的更改(上一个命令)。

如果容器是没有状态的,你就能更改Dockerfiler然后快速并且容易地重新构建容器。

参考链接:

  • Dockerfile参考文档(https://docs.docker.com/engine/reference/builder/)

  • Dockerfile编写的最佳实践(https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/)

5. 多个容器

一般情况下你的应用可能不止包含一个容器,你可能需要多个容器来提供其他服务,如数据库、web service、后台任务等。这时候我们可以使用docker-compose命令。

这里是一个docker-compose.yml(通常位于项目的根目录下面)的例子,用来构建一个Wordpress的应用。

version: '2'
services:
db:
image: mysql:5.7
volumes:
  - "./.data/db:/var/lib/mysql"
restart: always
environment:
  MYSQL_ROOT_PASSWORD: wordpress
  MYSQL_DATABASE: wordpress
  MYSQL_USER: wordpress
  MYSQL_PASSWORD: wordpress

wordpress:
depends_on:
  - db
image: wordpress:latest
links:
  - db
ports:
  - "8000:80"
restart: always
environment:
  WORDPRESS_DB_HOST: db:3306
  WORDPRESS_DB_PASSWORD: wordpress

运行docker-compose up会创建两个容器,一个叫db,一个叫wordpress。他们将会位于同一个虚拟网络之下。

相关链接:

  • Docker Compose(https://docs.docker.com/compose/)

  • Compose file参考(https://docs.docker.com/compose/compose-file/)

  • Compose命令行参考(https://docs.docker.com/compose/reference/)

6. 容器网络

docker-compose构建的容器会处于同一个虚拟网络中。然而你也可以配置各种你想要的样子,但是有一些需要注意的地方:

容器(如果允许的话)会使用容器的名字作为主机名(hostname)。例如,如果wordpress容器想要连接到db容器,它会使用db作为主机名。

默认情况下,容器是不能连接到其他容器的,除非明确这样配置。要让wordpress服务能访问db服务,需要明确地在links属性中指定。

默认情况下,宿主操作系统不能访问容器中的端口。因为wordpress是一个web服务器,我们需要将容器内部的80端口映射到宿主机的8080端口。这意味着我们可以在宿主机的浏览器中通过localhost:8080访问到这个Wordpress应用。

参考链接:

理解的Docker容器的网络(http://elliot.land/docker-explained-simply)

总结

这篇文章非常简单地介绍了Docker。我希望能在以后的文章中就单独的主题做更加详细的介绍,所以敬请期待。

这里有一篇深度介绍容器和镜像(http://elliot.land/docker-explained-simply)的文档。

对『Hacker时间』感兴趣的同学可以扫码进群一起来讨论。

 
Hacker时间 更多文章 编辑器之战: Vim的复仇 HTTP\/2使移动端媒体加载速度提升3-15倍 我们为什么不用SSH登录一切呢?
猜您喜欢 淘宝技术部世界杯算法大赛赛况 七牛云图片CDN 被你忽略的神级好功能 2015年出现的十大流行Python库 【周六活动】测试knowledge大闯关,精美gift等你拿