├── .gitattributes ├── README.md └── docs ├── A Simple Way to Dockerize Applications(译).md ├── Docker_UI_Clients_Research.md ├── How to Create Flexible Services for a CoreOS Cluster with Fleet Unit Files.markdown ├── Windows 环境下搭建一个coreos集群.md ├── make_boot2docker.iso.md ├── 八种 Docker 开发模式(译).md ├── 利用 Vagrant 部署 CoreOS 和 Docker 容器(译).md └── 访问 Docker 容器的名字空间.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DockerPool web 资源站 2 | ======= 3 | 4 | 目前主要存放开源文档,各位在 docs 文件夹下面新建自己要写的内容,push 上来即可。 5 | -------------------------------------------------------------------------------- /docs/A Simple Way to Dockerize Applications(译).md: -------------------------------------------------------------------------------- 1 | # 一种Docker化应用程序的简单方法 # 2 | 3 | “Docker化”在本质上就是一个将应用程序运行在Docker容器中的过程。虽然大部分应用程序的Docker化并不复杂,但总有些重复性的问题需要解决。比如下面的两个问题: 4 | 5 | 1. 当应用程序依赖于配置文件时,能使配置文件使用系统的环境变量 6 | 2. 当应用程序默认将日志写入文件时,能使日志内容输出至标准输出(`STDOUT/STDERR`) 7 | 8 | 这篇文章会给各位介绍一位新朋友:`Dockerize`,它可以简化上述两个在Docker化过程经常遇到的问题。 9 | 10 | ## 问题 ## 11 | 12 | ### 配置文件 ### 13 | 14 | 许多应用程序的运行都依赖于配置文件,而很多配置文件的配置值都依赖于系统运行时的环境变量。比如:开发环境和生产环境的数据库连接配置是不同的。类似的,API keys和其他敏感配置在不同的运行环境下也是不同的。 15 | 16 | 我们原本有几种方法来处理docker容器间的环境差异: 17 | 18 | 1. 将包含不同环境变量的配置文件都嵌入到docker image里,然后通过一个控制变量决定运行时使用哪个配置文件(例如:`APP_CONFIG=/etc/dev.config`) 19 | 2. 运行时实时挂载存放有不同配置文件的数据卷 20 | 3. 使用封装好的脚本,利用`sed`等工具来实时修改配置文件中的变量 21 | 22 | 第一种方式并不理想,因为每次运行环境的变化都需要重建image。而且,将API keys、用户凭证等敏感信息存储在image中也并不安全。妥协于开发环境的配置必然会泄露生产环境的细节,在任何image中都应该避免这种情况。 23 | 24 | 第二种动态加载数据卷的方式能将配置信息与image隔离开,但会使部署复杂度大幅提高,因为你不能只通过部署image来解决问题,还必须同时配合配置文件的修改。 25 | 26 | 第三种实时修改配置文件的方式也并不那么简单,有时你需要精心设计一行`sed`命令或写一个自定义的脚本才能做到这一点。虽然这会产生一个可以在docker生态系统中工作良好的image,但这是个重复性工作。 27 | 28 | ### 日志 ### 29 | 30 | Docker容器可以将标准输出(`STDOUT/STDERR`)记录下来,便于调试故障、监控并整合至[集中式日志系统](http://jasonwilder.com/blog/2012/01/03/centralized-logging/)中去,并可以通过`docker logs`命令或者docker log API调用来查看日志内容。如果应用程序将日志记录在标准输出(`STDOUT/STDERR`),我们可以使用很多工具来自动拉取docker日志并保存下来。 31 | 32 | 不幸的是,很多应用程序默认都将日志记录在文件里。虽然有一些[变通方法](http://jasonwilder.com/blog/2014/03/17/docker-log-management-using-fluentd/),但想找出各个应用程序间日志配置的差异仍然是件沉闷乏味的事。 33 | 34 | ## 使用Dockerize ## 35 | 36 | [Dockerize](https://github.com/jwilder/dockerize)是一个用Go语言开发的程序,它能够使docker化更简单: 37 | 38 | 1. 在启动时通过模板文件和容器内环境变量来生成配置文件 39 | 2. 可以将任意的日志文件输出至标准输出(`STDOUT/STDERR`) 40 | 3. 启动一个运行在容器内的进程 41 | 42 | ### 样例 ### 43 | 44 | 下面我们通过docker化一个普通的nginx容器来说明`dockerize`是如何工作的。首先安装nginx: 45 | 46 | FROM ubuntu:14.04 47 | 48 | # Install Nginx. 49 | RUN echo "deb http://ppa.launchpad.net/nginx/stable/ubuntu trusty main" > /etc/apt/sources.list.d/nginx-stable-trusty.list 50 | RUN echo "deb-src http://ppa.launchpad.net/nginx/stable/ubuntu trusty main" >> /etc/apt/sources.list.d/nginx-stable-trusty.list 51 | RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C300EE8C 52 | RUN apt-get update 53 | RUN apt-get install -y nginx 54 | 55 | RUN echo "daemon off;" >> /etc/nginx/nginx.conf 56 | 57 | EXPOSE 80 58 | 59 | CMD nginx 60 | 61 | 62 | 然后我们来安装`dockerize`,并通过`dockerize`启动nginx: 63 | 64 | FROM ubuntu:14.04 65 | 66 | # Install Nginx. 67 | RUN echo "deb http://ppa.launchpad.net/nginx/stable/ubuntu trusty main" > /etc/apt/sources.list.d/nginx-stable-trusty.list 68 | RUN echo "deb-src http://ppa.launchpad.net/nginx/stable/ubuntu trusty main" >> /etc/apt/sources.list.d/nginx-stable-trusty.list 69 | RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C300EE8C 70 | RUN apt-get update 71 | RUN apt-get install -y wget nginx 72 | 73 | RUN echo "daemon off;" >> /etc/nginx/nginx.conf 74 | 75 | RUN wget https://github.com/jwilder/dockerize/releases/download/v0.0.1/dockerize-linux-amd64-v0.0.1.tar.gz 76 | RUN tar -C /usr/local/bin -xvzf dockerize-linux-amd64-v0.0.1.tar.gz 77 | 78 | ADD dockerize /usr/local/bin/dockerize 79 | 80 | EXPOSE 80 81 | 82 | CMD dockerize nginx 83 | 84 | Nginx默认会把日志存放在`/var/log/nginx`下。但如果能把nginx的访问日志和错误日志输出至控制台,在使用交互模式运行nginx容器或者使用`docker logs nginx`命令查看日志时就会非常方便。 85 | 86 | 我们可以在执行命令时传入`-stdout ` 和 `-stderr `参数来实现上述功能。想输出多个日志文件内容时可以多次传入。 87 | 88 | CMD dockerize -stdout /var/log/nginx/access.log -stderr /var/log/nginx/error.log nginx 89 | 90 | 91 | 现在当你运行容器时,就可以通过`docker logs nginx`来查看nginx的日志了。 92 | 93 | 94 | 下面我们来讲解模板文件的用法。比如我们要使用环境变量来配置一个通用的代理服务器地址,定义一个URL作为环境变量`PROXY_URL`的值如下: 95 | 96 | PROXY_URL="http://jasonwilder.com" 97 | 98 | 99 | 当包含这个环境变量的容器启动时,`dockerize`会使用这个变量自动生成nginx服务器的location路径。 100 | 101 | 模板文件如下: 102 | 103 | server { 104 | listen 80 default_server; 105 | listen [::]:80 default_server ipv6only=on; 106 | 107 | root /usr/share/nginx/html; 108 | index index.html index.htm; 109 | 110 | # Make site accessible from http://localhost/ 111 | server_name localhost; 112 | 113 | location / { 114 | access_log off; 115 | proxy_pass {{ .Env.PROXY_URL }}; 116 | proxy_set_header X-Real-IP $remote_addr; 117 | proxy_set_header Host $host; 118 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 119 | } 120 | } 121 | 122 | 123 | 最终的Dockerfile如下: 124 | 125 | FROM ubuntu:14.04 126 | 127 | # Install Nginx. 128 | RUN echo "deb http://ppa.launchpad.net/nginx/stable/ubuntu trusty main" > /etc/apt/sources.list.d/nginx-stable-trusty.list 129 | RUN echo "deb-src http://ppa.launchpad.net/nginx/stable/ubuntu trusty main" >> /etc/apt/sources.list.d/nginx-stable-trusty.list 130 | RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C300EE8C 131 | RUN apt-get update 132 | RUN apt-get install -y wget nginx 133 | 134 | RUN echo "daemon off;" >> /etc/nginx/nginx.conf 135 | 136 | RUN wget https://github.com/jwilder/dockerize/releases/download/v0.0.1/dockerize-linux-amd64-v0.0.1.tar.gz 137 | RUN tar -C /usr/local/bin -xvzf dockerize-linux-amd64-v0.0.1.tar.gz 138 | 139 | ADD default.tmpl /etc/nginx/sites-available/default.tmpl 140 | 141 | EXPOSE 80 142 | 143 | CMD dockerize -template /etc/nginx/sites-available/default.tmpl:/etc/nginx/sites-available/default -stdout /var/log/nginx/access.log -stderr /var/log/nginx/error.log nginx 144 | 145 | 146 | 147 | `-template :` 参数表示:模板文件`/etc/nginx/sites-available/default.tmpl` 应该被解析修改并生成至`/etc/nginx/sites-available/default`。`Dockerize`支持同时使用多个模板文件。 148 | 149 | 使用下面的命令启动容器: 150 | 151 | $ docker run -p 80:80 -e PROXY_URL="http://jasonwilder.com" --name nginx -d nginx 152 | 153 | 154 | 然后尝试访问`http://localhost` 来验证代理配置是否生效。 155 | 156 | 以上是个最简单的样例,当然还可以使用`Dockerize`内嵌的`split`函数和`range`语句来处理多个proxy值或其他参数来扩展这个样例。[这里](https://github.com/jwilder/dockerize#using-templates)还有一些模板函数供参考。 157 | 158 | ## 总结 ## 159 | 160 | 虽然上述样例有些简单,但许多应用程序若想在docker体系下运行良好还需要一些小补充。`Dockerize`就是这样一个会对你有所帮助的小工具。 161 | 162 | 你可以在[jwilder/dockerize](https://github.com/jwilder/dockerize)下载源代码。 163 | 164 | 165 | 166 | 原文链接: [A Simple Way to Dockerize Applications](http://jasonwilder.com/blog/2014/10/13/a-simple-way-to-dockerize-applications/) 167 | 168 | 169 | -------------------------------------------------------------------------------- /docs/Docker_UI_Clients_Research.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2014-12-22 3 | tags: docker, ui 4 | author: fundon 5 | --- 6 | 7 | # Docker UI 客户端调研 8 | 9 | 10 | ## 调研 11 | 12 | 13 | ### [DockerUI][] 14 | 15 | DockerUI,目前功能比较简单,docker 的一个 web 接口 16 | 17 | - 作者:[crosbymichael][],Docker 员工 18 | 19 | - 功能: 20 | 21 | * Dashboard 22 | - 列出正在运行的 Containers 23 | - 统计 Containers 24 | - 统计 Images 25 | 26 | * Containers 27 | - 操作 28 | - Start/Stop 29 | - Pause/Unpause 30 | - Kill 31 | - Remove 32 | - 基本信息、运行状态 33 | 34 | * Images 35 | - 操作 36 | - 删除 37 | - 创建 Container 38 | - 添加 Tag 39 | - 基本信息 40 | 41 | 42 | ### [Shipyard][] 43 | 44 | Shipyard,可组合的 Docker 管理工具 45 | 46 | - 作者:[ehazlett][] 47 | 48 | - 功能: 49 | 50 | * Dashboard 51 | - 列出集群中CPU总共使用率 52 | - 列出集群中内存总共使用率 53 | - 最新操作日志 54 | 55 | * Containers 56 | - 列出集群中所有运行的容器(ID,Name,Image,Engine,CPUs,Memory,State,Type) 57 | - 操作 58 | - 发布新的容器,支持所有Docker参数,并支持调度,以及容器初始个数。 59 | - Restart/Stop 60 | - Destory 61 | - Scale 62 | - Logs 63 | 64 | * Engines 65 | - 列出集群中所有引擎(主机) 66 | - 操作 67 | - 添加新引擎(使用docker TCP绑定,CPUs,Memory信息) 68 | - 删除引擎 69 | 70 | * Events 71 | - 列出集群中所有引擎中容器的操作日志 72 | - 清除日志 73 | 74 | 75 | ### [Kitematic][] 76 | 77 | Kitematic,Mac 上的一个简单的 Docker 管理器 78 | 79 | - 作者:[@kitematic][] 80 | 81 | - 功能: 82 | 83 | * Containers 84 | - 创建 Container,从 Images 列表中选择需要的 Source Image 85 | - Container 86 | * 查看暴露的端口 87 | * Volumes 88 | * Terminal,打开终端,访问 Container bash 89 | * Stop 90 | * Restart 91 | * Logs 92 | * Settings 93 | - Ports 94 | - 设置环境变量 95 | - Volumes,开启/禁用 96 | - 删除 Container 97 | 98 | * Images 99 | - 创建 Image,可以导入包含 `Dockerfile` 文件的目录,进行 Build Image 100 | - 列出 Images 101 | - Image 102 | - 创建 Container 103 | - 日志信息 104 | - 删除 105 | - 改变目录,重新 Build Image 106 | - 基本状态信息 107 | 108 | * Settings 109 | - Boot2Docker VM 磁盘、内存使用率 110 | - Report issue 111 | 112 | - 技术栈: 113 | 114 | * [boot2docker][] 115 | 116 | * [Atom-Shell][] 117 | 118 | * [Meteor][] 119 | 120 | 121 | ### [Gaudi][] 122 | 123 | Gaudi,一个可视化的结构生成器,一个管弦乐演奏家 124 | 使用它可以简单快速启动任何类型的应用,不需要 Docker 和系统配置知识,通过 **link** 的方式关联它们 125 | 126 | - 作者:[marmelab][] 127 | 128 | - 功能: 129 | 130 | * Builder 131 | 132 | - 组件(component),多个组件模板供选择 133 | 134 | * 可托拽 135 | * 可配置 136 | * 可删除 137 | * 可关联(**link**)其他组件 138 | 139 | - `.gaudi.yml`(yml)配置文件 140 | 141 | * 组件变动,实时更新 142 | * 复制、剪贴 143 | * 下载 144 | 145 | * `gaudi` cli 146 | 147 | 根据 `.gaudi.yml` 文件描述,自动创建 Containers,并且 link 它们,快速构建一个 app 或者 服务,这点类似 [fig][] 148 | 149 | 150 | ### [Juju][] 151 | 152 | Juju,自动化你的云基础设施 153 | 通过 GUI 可视化工具或者命令行工具设计、创建、配置、部署、管理你的基础设施,使你能够专注的创造神奇的应用 154 | 155 | - 作者:[ubuntu][] 156 | 157 | - 功能: 158 | 159 | * Charms 160 | 有个 Charms Store,你可以选择你需要的应用 161 | 162 | * Configure 163 | 把需要的 Charm 托拽都画布中,在部署前,可以修改这些服务的配置 164 | 165 | * Deploy 166 | 简单单击(或者执行命令从命令行中)就可以在几秒钟把这些服务部署到目标云 167 | 可以看到启动进度和错误 168 | 169 | * Build relations 170 | 可以关联这些服务,构建一个应用架构,每个 Charm 都知道如何去连接其他 Charms 171 | 172 | * Monitor 173 | 174 | * Diagnose 175 | 176 | * Scaling 177 | 178 | * Added intelligence with Landscape 179 | 180 | * Import and export your environments 181 | 182 | - [Try Juju][] 183 | 184 | 185 | ### [Seagull][] 海鸥 186 | 187 | 海鸥是Docker的最佳小伙伴,它为Docker实现了一套Web监控页面 188 | 189 | - 作者:[tobegit3hub][] 190 | 191 | - 功能: 192 | 193 | * Containers 194 | - 列出 195 | - 筛选 196 | - Container 197 | * Stop 198 | * Refresh 199 | * 基本信息 200 | * 运行状态 201 | 202 | * Images 203 | - 列出 204 | - 筛选 205 | - 删除 Image 206 | - Image 207 | * 基本信息 208 | 209 | * Configuration 210 | Go,Docker,HTTP API 信息 211 | 212 | * DockerHub 213 | - 列出当前使用到 DockerHub 中的镜像 214 | - 筛选 215 | 216 | * Export JSON File 217 | 218 | * More 219 | - English 220 | - Chinese 221 | 222 | - [Try Seagull][] 223 | 224 | 225 | 226 | ### [Dockerboard][] 227 | 228 | Dockerboard,一个可视化的平台,让你的 Dockers 操作变的更简单。 229 | 用可视化的方式,来构建的 Docker 服务。 230 | 231 | **已经支持 Containers, Images 的基本操作; 其他功能还在开发中,不但只是单机操作。** 232 | 233 | - 创建者:[fundon][],[DockerPool][] 成员 234 | 235 | - 功能: 236 | 237 | * 后端 - [dockerboard APIs][] 238 | 239 | * 前端 - [bluewhale Web][] 240 | * Dashboard 241 | * Containers 242 | - 列表 243 | - 删除 244 | - Start/Stop 245 | - Pause/Unpause 246 | * Images 247 | - 列表 248 | - 删除 249 | * Canvas 250 | 251 | - [dockerboard.wiki][] - 更多详情请看 wiki 252 | 253 | 254 | 255 | ## 笔者 256 | 257 | - [@fundon](https://twitter/_fundon) 258 | - [GitHub](https://github.com/fundon) 259 | - cfddream#gmail.com 260 | 261 | 262 | [dockerui]: https://github.com/crosbymichael/dockerui 263 | [crosbymichael]: https://github.com/crosbymichael 264 | [shipyard]: https://github.com/shipyard/shipyard 265 | [ehazlett]: https://github.com/ehazlett 266 | [Kitematic]: https://kitematic.com 267 | [Kitematic Team]: https://github.com/kitematic 268 | [@kitematic]: https://twitter.com/kitematic 269 | [Atom-Shell]: https://github.com/atom/atom-shell 270 | [boot2docker]: https://github.com/boot2docker 271 | [meteor]: https://www.meteor.com 272 | [Gaudi]: http://gaudi.io 273 | [marmelab]: https://github.com/marmelab 274 | [fig]: http://fig.sh 275 | [juju]: http://juju.ubuntu.com/ 276 | [ubuntu]: http://juju.ubuntu.com/ 277 | [try juju]: https://demo.jujucharms.com 278 | [seagull]: https://github.com/tobegit3hub/seagull 279 | [tobegit3hub]: https://github.com/tobegit3hub 280 | [try seagull]: http://96.126.127.93:10086 281 | [dockerboard]: https://github.com/dockerboard 282 | [dockerpool]: https://github.com/dockerpool 283 | [dockerboard apis]: https://github.com/dockerboard/dockerboard 284 | [dockerboard.wiki]: https://github.com/dockerboard/dockerboard/wiki 285 | [bluewhale web]: https://github.com/dockerboard/bluewhale 286 | [fundon]: https://github.com/fundon -------------------------------------------------------------------------------- /docs/How to Create Flexible Services for a CoreOS Cluster with Fleet Unit Files.markdown: -------------------------------------------------------------------------------- 1 | # 如何通过fleet unit files 来构建灵活的服务 2 | ## 简介 3 | 4 | 原文地址:[How to Create Flexible Services for a CoreOS Cluster with Fleet Unit Files][],有删减。 5 | 6 | CoreOS利用一系列的工具,大大简化了集群和Docker服务的管理。其中,Etcd将独立的节点连接起来,并提供一个存储全局数据的地方。大部分实际的服务管理和管理员任务则有fleet来负责。 7 | 8 | 在[上一个guide][]中,我们过了一遍fleetctl的基本使用:操纵服务和集群中的节点。在那个guide中,我们简单的介绍了fleet unit文件,fleet使用它来定义服务。还创建一个简单的unit 文件,展示了如何使用fleetctl提供一个工作的service。 9 | 10 | 在本guide中,我们深度学习fleet unit文件,了解一些使你的service更加健壮的技巧。 11 | 12 | ## 准备 13 | 14 | 为了完成本教程,我们假设你已经根据[我们以往的教程][]创建了一个CoreOS集群,假定集群包含以下主机: 15 | 16 | - coreos-1 17 | - coreos-2 18 | - coreos-3 19 | 20 | 尽管本教程的大部分内容是关于unit文件的创建,但在描述unit文件中指令(属性)的作用时会用到这些机器。我们同样假设你阅读了[如何使用fleetctl][],你已经可以使用fleetctl将unit文件部署到集群中。 21 | 22 | 当你已经做好这些准备后,请继续阅读本教程。 23 | 24 | ## unit文件的section和类型 25 | 26 | 因为fleet的服务管理方面主要依赖于集群节点本地的systemd,所以systemd unit file基本就是 fleet unit file。 27 | 28 | fleet unit file 有许多类型,service是最常用的一种。这里列出一些 systemd unit file支持的类型,每个类型(文件)以"文件名.类型名"标识(命名)。比如example.service 29 | 30 | - service 31 | - socket 32 | - device 33 | - mount 34 | - automount 35 | - timer 36 | - path 37 | 38 | 尽管这些类型都是有效的,但service类型用的最多。在本guide中,我们也只讨论service类型的配置。 39 | 40 | unit 文件是简单的文本文件,以"文件名.类型名(上面提到的)"命名。在文件内部,它们以section 组织,对于fleet,大部分unit 文件是以下格式: 41 | 42 | [Unit] 43 | generic_unit_directive_1 44 | generic_unit_directive_2 45 | 46 | [Service] 47 | service_specific_directive_1 48 | service_specific_directive_2 49 | service_specific_directive_3 50 | 51 | [X-Fleet] 52 | fleet_specific_directive 53 | 54 | 55 | **每个小节的头和其他部分都是大小写敏感的**。unit小节用来定义一个unit文件的通用信息,在unit小节定义的信息对所有类型(比如service)都通用。 56 | 57 | Service小节用来设置一些只有Service类型文件才用到的指令,上面提到的每一个类型(但不是全部)(比如service和socket)都有相应的节来定义本类型的特定信息。 58 | 59 | fleet根据X-Fleet小节来判定如何调度unit文件。在该小节中,你可以设定一些条件来将unit文件部署到某台主机上。 60 | 61 | ## Building the Main Service 62 | 63 | 在本节,我们的unit文件将和 [basic guide on running services on CoreOS][]中提到的有所不同。这个文件叫apache.1.service,具体内容如下: 64 | 65 | [Unit] 66 | Description=Apache web server service 67 | 68 | # Requirements 69 | Requires=etcd.service 70 | Requires=docker.service 71 | Requires=apache-discovery.1.service 72 | 73 | # Dependency ordering 74 | After=etcd.service 75 | After=docker.service 76 | Before=apache-discovery.1.service 77 | 78 | [Service] 79 | # Let processes take awhile to start up (for first run Docker containers) 80 | TimeoutStartSec=0 81 | 82 | # Change killmode from "control-group" to "none" to let Docker remove 83 | # work correctly. 84 | KillMode=none 85 | 86 | # Get CoreOS environmental variables 87 | EnvironmentFile=/etc/environment 88 | 89 | # Pre-start and Start 90 | ## Directives with "=-" are allowed to fail without consequence 91 | ExecStartPre=-/usr/bin/docker kill apache 92 | ExecStartPre=-/usr/bin/docker rm apache 93 | ExecStartPre=/usr/bin/docker pull username/apache 94 | ExecStart=/usr/bin/docker run --name apache -p ${COREOS_PUBLIC_IPV4}:80:80 \ 95 | username/apache /usr/sbin/apache2ctl -D FOREGROUND 96 | 97 | # Stop 98 | ExecStop=/usr/bin/docker stop apache 99 | 100 | [X-Fleet] 101 | # Don't schedule on the same machine as other Apache instances 102 | X-Conflicts=apache.*.service 103 | 104 | 我们先说unit section,在本seciton,描述了unit 的基本信息和依赖情况。服务启动前有一系列的requirements,并且本例中使用的是hard requirements。如果我们想让fleet在启动本服务时启动其它服务,并且如果其他服务启动失败不影响本服务的启动,我们可以使用Wants来代替requirements。 105 | 106 | 接下来,我们明确的列出了requirements 启动的顺序。在服务运行前,确定其依赖的服务是可用的非常重要。我们也是通过这种方式来启动一个该服务的所有的从服务(Sidekick Service,后文会提到)。 107 | 108 | 在service 小节中,我们关闭了服务启动间隔时间。因为当服务开始在一个节点上运行时,相应镜像需要先从doker registry中pull下来,pull的时间会被计入startup timeout。这个值默认是90秒,通常是足够的。但对于比较复杂的容器来说,可能需要更长时间。 109 | 110 | 我们把killmode 设置为none,这是因为正常的kill 模式有时会导致容器移除命令执行失败(尤其是执行`docker --rm containerID/containername`时),这会导致下次启动时出问题。 111 | 112 | 我们把environment 文件也“拉进水”,这样我们就可以访问COREOS_PUBLIC_IPV4。如果服务创建时私有网络可用,`COREOS_PRIVATE_IPV4`是可配的,我们便可以使用每个主机自己的信息配置其container。 113 | 114 | ExecStartPre 用来清除上次运行的残留,确保本次的执行环境是干净的。对于头两个ExecStartPre 使用“=-”,来告诉systemd:即使这两个命令执行失败了,也继续执行接下来的命令。这样,docker 将尝试kill 并且 移除先前的容器,没有发现容器也没有关系。最后一个ExecStartPre用来确保将要运行的container是最新的。 115 | 116 | X-fleet section包含一个简单的条件,强制fleet将service调度某个没有运行Apache 服务的机器上。这样可以很容易的提高服务的可靠性,因为它们运行在不同的机器上(一个机器挂了,还有另外的机器在运行该服务)。 117 | 118 | 119 | ## Building the Sidekick Announce Service 120 | 121 | 现在当我们构建主unit文件时候,已经有了一些不错的想法。接下来,我们看一下传统的从service。这个从 service和主 serivce有一定联系,被用来向etcd注册服务。 122 | 123 | 这个文件,就像它在主unit文件中被引用的那样,叫做`apache-discovery.1.service`,内容如下: 124 | 125 | [Unit] 126 | Description=Apache web server etcd registration 127 | 128 | # Requirements 129 | Requires=etcd.service 130 | Requires=apache.1.service 131 | 132 | # Dependency ordering and binding 133 | After=etcd.service 134 | After=apache.1.service 135 | BindsTo=apache.1.service 136 | 137 | [Service] 138 | 139 | # Get CoreOS environmental variables 140 | EnvironmentFile=/etc/environment 141 | 142 | # Start 143 | ## Test whether service is accessible and then register useful information 144 | ExecStart=/bin/bash -c '\ 145 | while true; do \ 146 | curl -f ${COREOS_PUBLIC_IPV4}:80; \ 147 | if [ $? -eq 0 ]; then \ 148 | etcdctl set /services/apache/${COREOS_PUBLIC_IPV4} \'{"host": "%H", "ipv4_addr": ${COREOS_PUBLIC_IPV4}, "port": 80}\' --ttl 30; \ 149 | else \ 150 | etcdctl rm /services/apache/${COREOS_PUBLIC_IPV4}; \ 151 | fi; \ 152 | sleep 20; \ 153 | done' 154 | 155 | # Stop 156 | ExecStop=/usr/bin/etcdctl rm /services/apache/${COREOS_PUBLIC_IPV4} 157 | 158 | [X-Fleet] 159 | # Schedule on the same machine as the associated Apache service 160 | X-ConditionMachineOf=apache.1.service 161 | 162 | 和讲述主service一样,先从文件的unit节开始。依赖关系和启动顺序就不谈了。 163 | 164 | 第一个新的指令(参数)是`BindsTo=`,这个指令意味着 165 | 当fleet start、stop和restart `apache.1.service`时,对`apache-discovery.1.service`也做同样操作。这意味着,我们使用fleet 只操作一个主服务,即同时操作了主服务与与之"BindsTo"的服务。并且,这个机制是单向的,fleet操作`apache-discovery.1.service`对 `apache.1.service`没有影响。 166 | 167 | 对于service节,我们应用了`/etc/environment`文件,因为我们需要它包含的环境变量。`ExecStart=`在此处是一个bash脚本,它企图使用暴漏的ip和端口访问主服务。 168 | 169 | 如果连接成功,使用etcdctl设置etcd中key为`/services/apache/{COREOS_PUBLIC_IPV4}`的值为一个json串:`{"host": "%H", "ipv4_addr": ${COREOS_PUBLIC_IPV4}, "port": 80}`。这个key值的有效期为30s,以此来确保一旦这个节点down掉,etcd中不会残留这个key值的信息。如果连接失败,则立即从etcd移除key值,因为主服务已经失效了。 170 | 171 | 循环有20s的休息时间,每隔20秒(在30s内etcd中key失效之前)重新检查一下主服务是否有效并重置key。这将更新ttl时间,确保在下一个30秒内key值是有效的。 172 | 173 | 本例中,stop指令仅仅是将key从etcd中移除,当stop主服务时,因为`BIndsTo=`,本服务也将被执行,从而从etcd移除注册信息。 174 | 175 | 对于X-fleet小节,我们需要确保该unit和主unit运行在一台机器上。结合`BindsTo=`指令,这样做可以将主节点信息汇报到远程主机上。 176 | 177 | 178 | 179 | 180 | ## Fleet-Specific Considerations 181 | 182 | 183 | X-Fleet小节用来描述如何调度unit文件,具有以下指令(属性): 184 | 185 | - X-ConditionMachineID: 它可以指定一个特定的machine来加载unit。 186 | 187 | - X-ConditionMachineOf: 它用来设定将unit部署到运行某个特定unit的machine上。 188 | 189 | - X-Conflicts: 这个和上一个参数的作用恰恰相反, 它指定了本unit不想和哪些unit运行在同一台机器上。 190 | 191 | - X-ConditionMachineMetadata: 它基于machine的metadata来确定调度策略。 192 | 193 | - Global: 是一个布尔值,用来确定你是否想把unit部署到集群的每一台machine上。 194 | 195 | 这些额外的directives(属性)让管理员灵活的在集群上部署服务,在unit被提交到machinie的systemd实例之前,(directives)指定的策略将会被执行。 196 | 197 | 还有一个问题,什么时候使用fleet来部署相关的unit。除了X-fleet 小节外,fleetctl工具不检查units之间的依赖是否满足。因此在使用fleet部署相关的unit时,会有一些有趣的问题。 198 | 199 | 这意味着,尽管fleetctl工具会执行必要的步骤直到unit变成期望的状态:提交,加载,执行unit中的命令。但不会解决unit之间的依赖问题。 200 | 201 | 所以,如果你同时提交了主从两个unit:A和B,但A和B还没有加载。执行`fleetctl start A.service`将加载并执行`A.service` unit。然而,因为`B.service` unit还没有加载,并且因为fleetctl 不会检查unit之间的依赖,`A.service`将会执行失败。因为systemd会检查依赖是否满足,一旦主机的systemd开始执行`A.service`,却没有找到`B.service`,systemd便会终止`A.service`的执行。 202 | 203 | 为了避免这种伙伴unit执行失败的情况,你可以手动同时启动两个unit`fleet start A.service B.service` ,不要依赖`BindsTo=`执令。 204 | 205 | 另一种方法是当运行主unit的时候,确保从unit至少已经被加载。**被加载意味着一台machine已经被选中,并且unit file已被提交到systemd实例**,此时满足了依赖条件,`BindsTo`参数也能够正确执行。 206 | 207 | fleetctl load A.service B.service 208 | fleetctl start A.service 209 | 210 | 如果fleetctl执行多个unit时失败,请记起这一点。 211 | 212 | ## Instances and Templates 213 | 214 | unit template是fleet一个非常有用的概念。 215 | 216 | unit templates依赖systemd一个叫做"instance"的特性。systemd运行时通过计算template unit文件实例化的unit file。template文件和普通unit文件大致相同,只有一点改进。但如果正确使用,威力无穷。 217 | 218 | 你可以在文件名中加入"@"来标识一个template 文件,比如一个传统的service文件名:`unit.service`,对应template文件则可以叫做`unit@.service`。 219 | 当template文件被实例化的时候,在"@"和".service"之间将有一个用户指定的标识符:`unit@instance_id.service`。在template文件内部,可以用%p来指代文件名(即unit),类似的,%i可以指代标识符(即instance_id)。 220 | 221 | ## Main Unit File as a Template 222 | 223 | 我们可以创建一个template文件:apache@.service。 224 | 225 | [Unit] 226 | Description=Apache web server service on port %i 227 | 228 | # Requirements 229 | Requires=etcd.service 230 | Requires=docker.service 231 | Requires=apache-discovery@%i.service 232 | 233 | # Dependency ordering 234 | After=etcd.service 235 | After=docker.service 236 | Before=apache-discovery@%i.service 237 | 238 | [Service] 239 | # Let processes take awhile to start up (for first run Docker containers) 240 | TimeoutStartSec=0 241 | 242 | # Change killmode from "control-group" to "none" to let Docker remove 243 | # work correctly. 244 | KillMode=none 245 | 246 | # Get CoreOS environmental variables 247 | EnvironmentFile=/etc/environment 248 | 249 | # Pre-start and Start 250 | ## Directives with "=-" are allowed to fail without consequence 251 | ExecStartPre=-/usr/bin/docker kill apache.%i 252 | ExecStartPre=-/usr/bin/docker rm apache.%i 253 | ExecStartPre=/usr/bin/docker pull username/apache 254 | ExecStart=/usr/bin/docker run --name apache.%i -p ${COREOS_PUBLIC_IPV4}:%i:80 \ 255 | username/apache /usr/sbin/apache2ctl -D FOREGROUND 256 | 257 | # Stop 258 | ExecStop=/usr/bin/docker stop apache.%i 259 | 260 | [X-Fleet] 261 | # Don't schedule on the same machine as other Apache instances 262 | X-Conflicts=apache@*.service 263 | 264 | 265 | 就像你看到的,我们将`apache-discovery.1.service`改为`apache-discovery@%i.service`。即如果我们有一个unit文件`apache@8888.service`,它将需要一个从服务`apache-discovery@8888.service`。%i 曾被 实例化的标识符(即8888) 替换过。在这个例子中,%i也可以被用来指代服务的一些信息,比如apahce server运行时占用的端口。 266 | 267 | 为了使其工作,我们改变了`docker run`的参数,将container的80端口,映射给主机的某一个端口。在静态的unit 文件中,我们使用`${COREOS_PUBLIC_IPV4}:80:80`,将container的80端口,映射到主机${COREOS_PUBLIC_IPV4}网卡的80端口。在这个template 文件中,我们使用`${COREOS_PUBLIC_IPV4}:%i:80`,使用`%i`来说明我们使用哪个端口。在template文件中选择合适的instance identifier会带来很大的灵活性。 268 | 269 | container的名字被改为了基于instance ID的`apache.%i`,**记住container的名字不能够使用`@`标识符**。现在,我们校正了运行container用到的所有指令(参数)。 270 | 271 | 在X-Fleet小节,我们同样改变了部署信息来替代原先的配置。 272 | 273 | ## Sidekick Unit as a Template 274 | 275 | 将从unit文件模板化也是类似的过程,新的从unit文件叫`apache-discovery@.service`,内容如下: 276 | 277 | [Unit] 278 | Description=Apache web server on port %i etcd registration 279 | 280 | # Requirements 281 | Requires=etcd.service 282 | Requires=apache@%i.service 283 | 284 | # Dependency ordering and binding 285 | After=etcd.service 286 | After=apache@%i.service 287 | BindsTo=apache@%i.service 288 | 289 | [Service] 290 | 291 | # Get CoreOS environmental variables 292 | EnvironmentFile=/etc/environment 293 | 294 | # Start 295 | ## Test whether service is accessible and then register useful information 296 | ExecStart=/bin/bash -c '\ 297 | while true; do \ 298 | curl -f ${COREOS_PUBLIC_IPV4}:%i; \ 299 | if [ $? -eq 0 ]; then \ 300 | etcdctl set /services/apache/${COREOS_PUBLIC_IPV4} \'{"host": "%H", "ipv4_addr": ${COREOS_PUBLIC_IPV4}, "port": %i}\' --ttl 30; \ 301 | else \ 302 | etcdctl rm /services/apache/${COREOS_PUBLIC_IPV4}; \ 303 | fi; \ 304 | sleep 20; \ 305 | done' 306 | 307 | # Stop 308 | ExecStop=/usr/bin/etcdctl rm /services/apache/${COREOS_PUBLIC_IPV4} 309 | 310 | [X-Fleet] 311 | # Schedule on the same machine as the associated Apache service 312 | X-ConditionMachineOf=apache@%i.service 313 | 314 | 当主unit和从unit都是静态文件的时候,我们已经讲述了如何将从unit绑定到主unit,现在我们来讲下如何将实例化的从 unit绑定到同样根据模板实例化的主unit。 315 | 316 | 我们知道,`curl`命令可以被用来检查服务的有效性,为了让其连接到正确的url,我们用instance ID来代替80端口。这是非常必要的,因为在主unit中,我们改变了container映射的端口。 317 | 318 | 我们改变了写入到etcd的端口信息,同样是使用instance id来替换80端口。这样,设置到etcd的json信息就可以是动态的。它将采集service服务所在主机的hostname,ip地址和端口信息。 319 | 320 | 最后,我们也更改了X-Fleet小节,我们需要确定这个进程和其对应的主unit运行在一台主机上。 321 | 322 | ## Instantiating Units from Templates 323 | 324 | 实例化template文件有多种方法: 325 | 326 | fleet和systemd都可以处理链接,我们可以创建模板文件的链接文件: 327 | 328 | ln -s apache@.service apache@8888.service 329 | ln -s apache-discovery@.service apache-discovery@8888.service 330 | 331 | 这将创建两个链接,叫做`apache@8888.service` 和 `apache-discovery@8888.service`,每个文件都包含了fleet和systemd运行它们所需要的所有信息,我们可以使用`fleetctl`提交、加载和启动这些服务`fleetctl start apache@8888.service apache-discovery@8888.service`。 332 | 333 | 如果你不想使用链接文件的方式,可以直接使用`fleetctl`来提交模板文件:`fleetctl submit apache@.service apache-discovery@.service`,你可以在运行时为其赋予一个instance identifier,比如:`fleetctl start apache@8888.service apache-discovery@8888.service` 334 | 335 | 这种方式不需要链接文件,然而一些系统管理员偏好于使用链接文件的方式。因为链接文件一旦创建完毕便可以在任意时刻使用,并且,如果你将所有的链接文件放在一个地方,便可以在同一时刻启动所有实例。 336 | 337 | 假设我们将静态unit文件全放在static目录下,模板文件放在templates目录下,根据模板文件创建的链接文件全放在instances目录下,你就可以用`fleetctl start instances/*`一次启动所有的实例。如果你的服务很多的话,这将非常方便。 338 | 339 | ## 小结 340 | 341 | 通过本章,相信你对如何创建unit文件以及fleet的使用有了深入的了解。利用unit文件中灵活的指令(参数),你可以将你的服务分布化,将相互依赖的服务部署在一起,并将它们的信息注册到etcd中。 342 | 343 | ## 笔者信息 344 | 345 | 李乾坤,docker爱好者 346 | 347 | blog:[http://qiankunli.github.io/ ][] 348 | 349 | email:[qiankun.li@qq.com][] 350 | 351 | 352 | 353 | [我们以往的教程]: https://www.digitalocean.com/community/tutorials/how-to-set-up-a-coreos-cluster-on-digitalocean 354 | [如何使用fleetctl]: https://www.digitalocean.com/community/tutorials/how-to-use-fleet-and-fleetctl-to-manage-your-coreos-cluster 355 | [上一个guide]: https://www.digitalocean.com/community/tutorials/how-to-use-fleet-and-fleetctl-to-manage-your-coreos-cluster 356 | [basic guide on running services on CoreOS]: https://www.digitalocean.com/community/tutorials/how-to-create-and-run-a-service-on-a-coreos-cluster 357 | [How to Create Flexible Services for a CoreOS Cluster with Fleet Unit Files]: https://www.digitalocean.com/community/tutorials/how-to-create-flexible-services-for-a-coreos-cluster-with-fleet-unit-files 358 | [http://qiankunli.github.io/ ]: http://qiankunli.github.io/ 359 | [qiankun.li@qq.com]: qiankun.li@qq.com -------------------------------------------------------------------------------- /docs/Windows 环境下搭建一个coreos集群.md: -------------------------------------------------------------------------------- 1 | ## 前言 2 | 3 | 本文旨在windows + virtualbox 环境下搭建一个coreos集群,自娱自乐,如有错误,欢迎大家指正。 4 | 5 | 下面提到的某些步骤需要翻墙。 6 | 7 | 官网上明确表示"It's highly recommended that you set up a cluster of at least 3 machines — it's not as much fun on a single machine"。而通常一个分布式系统,都会有一个分布式存储系统来信息共享,从而将集群各个节点紧密联系起来。在CoreOS中,etcd便担此重任。 8 | 9 | 从某种方式讲,创建一个CoreOS集群,工作量占大头的就是配置好各节点的etcd服务,或者说是创建一个etcd集群。 10 | 11 | 创建集群的一个关键是,说清楚集群都包含哪些节点,有以下几种方式: 12 | 13 | 1. 每个节点都有一个配置文件,列出当前集群的节点(IP或主机名); 14 | 2. 指定一个节点,除该结点外,集群其它节点都向这个节点汇报自己的信息; 15 | 3. 大家都有一个身份标识,到第三方服务那里注册。 16 | 17 | 这几种方式各有利弊,第一种方式简单直接,但如果集群节点经常变化,那么第一种方式就不太合适了。而第二种和第三种,在etcd中分别被称为Static方式(通过制定 peers的IP 和端口创建)与 Discovery方式 (通过一个发现服务创建)。 18 | 19 | 而搭建CoreOS集群,有以下几种办法: 20 | 21 | 1. 先为每个节点安装CoreOS系统,然后配置etcd服务(可以通过命令行,也可以修改配置文件); 22 | 2. 在安装CoreOS时,就配置好etcd服务。即static方式或discovery方式。 23 | 24 | 25 | ## Static方式(通过ISO安装) 26 | 27 | ### 文件准备 28 | 29 | 1. 下载 [ISO][] 30 | 2. 使用puttygen等工具生成一对密钥。 31 | 3. 编写cloud-config.yaml 32 | 33 | 假设需要配置三台主机,IP地址分别是: 34 | 35 | coreos1 172.17.8.101 36 | 37 | coreos2 172.17.8.102 38 | 39 | coreos3 172.17.8.103 40 | 41 | 以coreos1的配置为例: 42 | 43 | #cloud-config 44 | hostname: coreos1 45 | coreos: 46 | etcd: 47 | name: coreos1 48 | peers: 172.17.8.102:7001 ## IP为172.17.8.102的主机不用配置该选项 49 | addr: 172.17.8.101:4001 50 | peer-addr: 172.17.8.101:7001 51 | units: 52 | - name: etcd.service 53 | command: start 54 | - name: fleet.service 55 | command: start 56 | - name: static.network 57 | content: | 58 | [Match] 59 | Name=enp0s8 60 | [Network] 61 | Address=172.17.8.101/24 62 | Gateway=172.17.8.1 63 | DNS=172.17.8.1 64 | users: 65 | - name: core 66 | ssh-authorized-keys: 67 | - 你的公钥 ##此处可以让三台主机使用同样的公钥 68 | - groups: 69 | - sudo 70 | - docker 71 | 72 | 编辑完毕后,请到[http://codebeautify.org/yaml-validator][]校验下yaml文件格式是否正确。 73 | 74 | ### 每台虚拟机安装过程 75 | 76 | 1. 根据下载ISO在virtualbox上创建一个虚拟机。并为其添加一个Host-Only网卡(网络地址要跟`cloud-config.yaml`中的一致)。 77 | 2. 虚拟机启动后,使用`sudo passwd root`命令配置root用户密码。 78 | 3. virtualbox新创的虚拟机默认使用NAT方式。因此可以配置端口映射,然后使用putty等shell工具登录该虚拟机。IP为localhost,端口是你刚刚端口映射配的,用户名是root,密码是你第二步配置的。 79 | 4. 现在我们以root用户登录了,使用`export http_proxy=http://xxxx`命令配置http_proxy代理,让你的机器可以访问外网。也可以不配置,但速度真的慢的要死。 80 | 5. 创建前面提到的cloud-config.yaml文件,运行`coreos-install -d /dev/sda -c ./cloud-config.yaml -v`命令(注意,不同虚拟机所用`cloud-config.yaml`文件不同),将coreos安装到虚拟硬盘,完毕后关闭虚拟机。 81 | 6. 配置虚拟机从硬盘启动(默认是从光盘启动的)。 82 | 7. 使用putty登录虚拟机,用户名为core,记得配置私钥喔。 83 | 84 | 85 | ## Discovery方式(通过Vagrant安装) 86 | 87 | Discovery方式需要用到etcd官方的Discovery服务,当然,我们也可以自己搭建一个私有的Discovery服务。这种方式的主要优点是,能够自动感知到集群节点的增减。 88 | 89 | ### 文件准备 90 | 91 | 1. 下载[Vagrant][]并安装。 92 | 2. 获取coreos集群的Token 93 | 94 | `curl https://discovery.etcd.io/new` 95 | 96 | 3. 通过 Git下载官方的 Vagrant 仓库 97 | 98 | 在git bash下执行`git clone https://github.com/coreos/coreos-vagrant.git` 99 | 100 | 3.1. 进入coreos-vagrant目录,将 user-data.sample 和 config.rb.sample 两个文件各拷贝一份,并去掉 .sample 后缀,得到 user-data 和 config.rb 文件。 101 | 102 | 3.2. 修改 config.rb 文件,配置 $num_instances 和 $update_channel 这两个参数。比如: 103 | 104 | $num_instances=3 ## 表示我们要创建3台主机 105 | $update_channel='stable' 106 | 107 | 3.3. 修改user-data文件(类似于上述的cloud-config.yaml文件) 108 | 109 | #cloud-config 110 | coreos: 111 | etcd: 112 | discovery: https://discovery.etcd.io/你的Token 113 | addr: $public_ipv4:4001 114 | peer-addr: $public_ipv4:7001 115 | fleet: 116 | public-ip: $public_ipv4 117 | units: 118 | - name: etcd.service 119 | command: start 120 | - name: fleet.service 121 | command: start 122 | 123 | 编辑完毕后,请到[http://codebeautify.org/yaml-validator][]校验下yaml文件格式是否正确。 124 | 125 | 3.4. 将Vagrantfile文件中的“config.vm.box_version = ">= 308.0.1"”注释掉 126 | 127 | 4. 下载[box文件][](本来不下载也可以的,但国内因为各种原因速度较慢,所以推荐用户使用浏览器等工具事先下载该文件,使用迅雷也是个不错的选择),将其放在coreos-vagrant目录下,并在其目录下执行 128 | 129 | vagrant box add coreos-stable coreos_production_vagrant.box 130 | 131 | 132 | ### 安装 133 | 134 | 进入coreos-vagrant目录,在git bash下执行`vagrant up`即可在virtualbox创建一个coreos集群了。 135 | 136 | 如何登录某台主机呢?执行`vagrant ssh-config --host core-01`,你可以看到core-01密钥文件被vagrant放到了哪里,然后就可以使用putty工具登录了。 137 | 138 | ## 推荐方式 139 | 140 | 上述第一种方式,安装过程中要下载文件(需访问外网),速度太慢。而discovery方式,需要自己搭建discovery服务(公有的discovery服务也需要能访问外网)。所有有了这个“使用vagrant + static”的方式。 141 | 142 | ### 准备过程 143 | 144 | 1. 下载[Vagrant][]并安装。 145 | 2. 通过 Git下载官方的 Vagrant 仓库 146 | 147 | 在git bash下执行`git clone https://github.com/coreos/coreos-vagrant.git` 148 | 149 | 2.1. 进入coreos-vagrant目录,将 user-data.sample 和 config.rb.sample 两个文件各拷贝一份,并去掉 .sample 后缀,得到 user-data 和 config.rb 文件。 150 | 151 | 2.2. 修改 config.rb 文件,配置 $num_instances 和 $update_channel 这两个参数。比如: 152 | 153 | $num_instances=1 154 | $update_channel='stable' 155 | 156 | 即,使用vagrant每次安装一台主机。 157 | 158 | 2.3. 修改user-data文件,针对安装的主机,采用第一种方式的cloud-config.yaml文件内容,每装一台,修改一次。 159 | 160 | 3. 修改Vagrantfile文件 161 | 162 | 3.1. 注释`config.vm.box_version = ">= 308.0.1"` 163 | 164 | 3.2. 修改`config.vm.define vm_name = "core-%02d" % i do |config|` 为`config.vm.define vm_name = "core-01" do |config|`,其中core-01为要安装主机的主机名,每装一台,修改一次。 165 | 166 | 3.3. 修改`ip = "172.17.8..#{i+100}"`为自己适合的网段(如果有必要的话)。 167 | 168 | 4. 下载[box文件][]并安装,`vagrant box add coreos-stable coreos_production_vagrant.box`。(参见第二种方式第四步) 169 | 5. 执行`vagrant up`,安装完毕后,使用putty登录,用户名为core,记得配置私钥。 170 | 171 | 当然,你也可以安装好一个CoreOS VM后,Clone下一个CoreOS VM,然后登陆并修改其相关配置即可。 172 | 173 | 174 | ## 小结 175 | 176 | 安装完毕后,可以进入某一台主机,使用`fleetctl list-machines`测试集群是否正常启动。本文涉及到比较多的知识点,比如: 177 | 178 | 1. cloud-config.yaml文件的作用及如何进行个性化配置 179 | 2. Static方式的工作原理 180 | 3. vagrant的工作机制 181 | 182 | 因为笔者现在也不是完全清楚,所以没有细写,欢迎大家交流。 183 | 184 | ## 引用 185 | 186 | 本文引用了其他博客或stack overflow上的成果,算是一个总结补充帖。但因为时间原因,一些已经忘记,部分引用如下: 187 | 188 | [http://wiselyman.iteye.com/blog/2152167][] 189 | 190 | [http://www.infoq.com/cn/articles/coreos-analyse-etcd][] 191 | 192 | [ISO]: https://coreos.com/docs/running-coreos/platforms/iso/ 193 | [http://codebeautify.org/yaml-validator]: http://codebeautify.org/yaml-validator 194 | [Vagrant]: https://www.vagrantup.com/downloads.html 195 | [box文件]: http://storage.core-os.net/coreos/amd64-usr/alpha/coreos_production_vagrant.box 196 | [http://wiselyman.iteye.com/blog/2152167]: http://wiselyman.iteye.com/blog/2152167 197 | [http://www.infoq.com/cn/articles/coreos-analyse-etcd]: http://www.infoq.com/cn/articles/coreos-analyse-etcd 198 | [http://qiankunli.github.io/]: http://qiankunli.github.io/ 199 | [qiankun.li@qq.com]: qiankun.li@qq.com 200 | [dockerpool]: http://www.dockerpool.com/ -------------------------------------------------------------------------------- /docs/make_boot2docker.iso.md: -------------------------------------------------------------------------------- 1 | # 定制自己的boot2docker.iso 2 | 3 | ## 前言 4 | 5 | 阅读本文,需要你对docker,Dockerfile,boot2docker-vm,virtualbox以及github等有一定了解。文章中如有错误,欢迎大家批评指正。 6 | 7 | ## 背景 8 | 9 | docker刚开始推出的时候,只支持ubuntu。也难怪,docker只支持虚拟linux container,人家本来就不是给windows玩的。但后来估计是为了推广docker的使用,我们可以下载[boot2docker.exe][],安装并运行它,会在virtualbox上创建一个boot2docker-vm,一个极精简的可以运行docker service的linux系统。 10 | 11 | 观察boot2docker-vm的设置,我们可以看到,boot2docker-vm以光盘方式启动,iso来自于你PC上的`/c/Users/yourname/.boot2docker/boot2docker.iso`。那么在实践中,我们可以自己制作iso并替换掉它。 12 | 13 | ## 为什么要定制 14 | 15 | 当然,你会怀疑这样做的必要性。确实没必要,如果你只是想玩一下docker的话。但考虑到在公司环境中要跟他人协作,情况也许就有所不同了。 16 | 17 | 笔者曾将一个系统转移到了docker上,并附上两页精美的guide。manager却问:“可以再精简点么?不是所有人都想知道细节的”。好吧,我最后把这个系统在boot2docker-vm上做成了一键启动。大家只要使用这个服务即可,而不用关心它的安装与执行过程。为达到这个目的,定制自己的boot2docker.iso就很有必要了。下面是一些具体的需求: 18 | 19 | ### 配置代理 20 | 21 | 如果你的PC运行在公司的内网中,那么很遗憾,你无法直接pull [docker官网][]上的image。So,你需要通过http_proxy环境变量配置代理。进而,如果贵公司有自己私有的docker-registry,还需要配置no_proxy环境变量,确保pull私有库的image时不必通过代理。 22 | 23 | ### 更改时区 24 | 25 | 如果在boot2docker-vm中执行`date`命令,你会发现显示时间比实际少了8个小时。在一些情况下,你需要一个正确的时间,相信我。 26 | 27 | ### 安装软件 28 | 29 | boot2docker-vm是一个非常精简的linux,很多linux命令没有安装。 30 | 31 | 以fig为例,早期的boot2docker-vm并不支持fig命令。即使现在,也是通过运行一个装有fig的容器的方式“委婉”的使用fig,并且这种方式还有一些使用限制。 32 | 33 | 再假设一个场景,系统需要运行容器A和容器B。容器B的运行依赖容器A中的服务ServiceA。但容器A启动后,serviceA的启动需要一定的时间。如何确保容器B启动时,serviceA已经启动完毕?一个比较low的方案是(如果有更好的方案,请及时告诉我): 34 | 35 | 1. 容器A使用`-v`和boot2docker-vm映射一个目录DirA; 36 | 2. boot2docker-vm使用inotifywait监控这个目录; 37 | 3. serviceA启动完毕后,向DirA中写入一个文件FileA。 38 | 4. inotifywait监控到FileA后,即认为serviceA已启动,于是启动容器B。 39 | 40 | 看来,boot2docker-vm有必要装一个inotifywait。 41 | 42 | 当然,你也可以运行一个ubuntu-vm,并在ubuntu-vm上安装docker服务来替代boot2docker-vm。这样,安装fig和inotifywait全不是问题。不过你确定所有同事都乐意在virtualbox或vmware上安装一个ubuntu vm。你会问“不是有vagrant么?”好吧,你确定所有同事都想知道vagrant是什么么?他们只想完成今天的工作,其它的还是由我们代劳吧。 43 | 44 | ### 添加脚本 45 | 46 | 我们可以自定义一个脚本,比如叫做start.sh,然后配置其在boot2docker-vm启动时执行,它能做很多事。 47 | 48 | 1. mount sharedfolder 49 | 50 | 有时候容器的运行需要操作你PC上的一些文件,一方面virtualbox需要配置sharedfolder,另一方面boot2docker-vm需要mount sharedfolder。而后者,start.sh可以代劳喔。 51 | 52 | 2. 触发容器的运行 53 | 54 | 在start.sh中写入启动容器的脚本。这时,只要启动boot2docker-vm,就可以触发容器的执行。这样,我们就可以在PC上使用容器提供的服务,使用者不需要操作boot2docker-vm,不需要对docker有任何了解。 55 | 56 | ## 如何定制 57 | 58 | ### 基本流程 59 | 60 | 执行如下命令 61 | 62 | $ docker pull boot2docker/boot2docker 63 | $ docker run --rm boot2docker/boot2docker > boot2docker.iso 64 | 65 | 你就可以得到一个默认的boot2docker.iso。 66 | 67 | 一言以蔽之,**制作boot2docker.iso的关键是`boot2docker/boot2docker`**。你可以登陆[https://github.com/][]搜索 `boot2docker/boot2docker`repositories。通过运行`boot2docker/boot2docker` image以及对其Dockerfile的观察我发现:`boot2docker/boot2docker` image `$ROOTFS`目录下的 目录结构跟 boot2docker-vm的目录结构一模一样。So,在`boot2docker/boot2docker` image下对`$ROOTFS`所做的更改,都将通过`makeiso.sh`制作到boot2docker.iso中。 68 | 69 | ### 配置案例 70 | 71 | FROM boot2docker/boot2docker 72 | ADD start.sh /start.sh 73 | # 更改boot2docker-vm的欢迎界面 74 | RUN echo "" >> $ROOTFS/etc/motd; \ 75 | echo "hello boot2docker vm" >> $ROOTFS/etc/motd; \ 76 | echo "" >> $ROOTFS/etc/motd 77 | # 配置http_proxy代理 78 | RUN echo "export http_proxy= your proxy" >> $ROOTFS/etc/profile 79 | # 配置启动脚本 80 | RUN echo "/start.sh" >> $ROOTFS/etc/profile 81 | RUN /make_iso.sh 82 | CMD ["cat", "boot2docker.iso"] 83 | 84 | 看到这里,我相信你可以根据自己的需求制作自己的boot2docker.iso了。 85 | 86 | ## 笔者信息 87 | 88 | 李乾坤,docker爱好者, 89 | blog:[http://qiankunli.github.io/][] 90 | email:[qiankun.li@qq.com][] 91 | 92 | [boot2docker.exe]: https://github.com/boot2docker/windows-installer/releases 93 | [docker官网]: https://hub.docker.com 94 | [https://github.com/]: https://github.com/ 95 | [http://qiankunli.github.io/]: http://qiankunli.github.io/ 96 | [qiankun.li@qq.com]: qiankun.li@qq.com 97 | -------------------------------------------------------------------------------- /docs/八种 Docker 开发模式(译).md: -------------------------------------------------------------------------------- 1 | Title: 八种 Docker 开发模式(译) 2 | date: 2014-10-25 3 | url: eight-docker-development-patterns 4 | tags: docker, pattern, cloud, devops 5 | toc: yes 6 | status: public 7 | 8 | 曾经我写过两篇文章:一篇是 [利用 OpenVZ 容器构建家庭云服务](http://www.hokstad.com/the-home-cloud);另一篇则提出 [服务器必须能够自动化重建](http://www.hokstad.com/rebuilding-the-build-server-on-every-build) 的新思路。后来 Docker 出现了,它能够保证每次重建环境的一致性,已然成了我的最爱。 9 | 10 | 这篇文章我将介绍自己使用 Docker 过程中不断重复的那些模式,我并不认为这些模式有多新奇,只希望它们能对各位有用,同时我也非常期待听到各位关于 Docker 使用的各种模式。 11 | 12 | Docker 实验的基础在于它能够将容器状态持久化到存储介质中,并且可在任意时候无损还原回来(除非修改容器状态时忘了更新 Dockerfile 文件,定期重建容器可避免这样的杯具)。 13 | 14 | ## 1. 可重用的基础容器 15 | 16 | Docker 鼓励使用继承特性,善用继承能大大减少构建容器的时间,这是高效使用 Docker 的关键。Docker 在缓存过程容器方面表现过于出色,因此经常错过分享和重用的机会。 17 | 18 | 在迁移其它容器到 Docker 的过程中,存在太多重复冗余的安装步骤;当项目需要部署到很多地方,或者项目运行周期较长,又或项目需要安装一些特定包时,我都会考虑为该项目创建单独的容器。长此以往,我有了很多的容器,并且数量仍在快速增加;我试图在 Docker 中运行一切(包括某些桌面应用),只为让宿主环境更加纯粹。 19 | 20 | 以上这些,促使我开始思考如何减少容器的构建时间。我开始从各种项目容器中提取基本安装步骤,构建适用各种场景的可重用容器。下面是 "devbase" 基础容器对应的 Dockerfile 文件: 21 | 22 | ```docker 23 | FROM debian:wheezy 24 | RUN apt-get update 25 | RUN apt-get -y install ruby ruby-dev build-essential git 26 | RUN apt-get install -y libopenssl-ruby libxslt-dev libxml2-dev 27 | 28 | # For debugging 29 | RUN apt-get install -y gdb strace 30 | 31 | # Set up my user 32 | RUN useradd vidarh -u 1000 -s /bin/bash --no-create-home 33 | 34 | RUN gem install -n /usr/bin bundler 35 | RUN gem install -n /usr/bin rake 36 | 37 | WORKDIR /home/vidarh/ 38 | ENV HOME /home/vidarh 39 | 40 | VOLUME ["/home"] 41 | USER vidarh 42 | EXPOSE 8080 43 | ``` 44 | 45 | 这段代码简单易懂:随便选择一个发行版,安装一些经常使用的工具,这些工具因人而异;开放容器的 `8080` 端口;新增一个用户,将其 `userid` 设置为服务器的用户ID,不创建 `/home` 目录;将 `/home` 目录设为共享文件夹,共享文件夹将在下一节介绍。 46 | 47 | ## 2. 支持共享文件夹的开发容器 48 | 49 | 为了方便开发,我的所有开发容器都至少有一个共享文件夹 `/home` 。凭借开发模式下的代码重载(code-reloader)特性,容器可以在运行时重载文件系统的改变,这样就不需要为每一次代码提交重启或者重建容器,当然你也可以偶尔重启容器来确认是否有所遗漏。对于测试和生产环境的容器,我不推荐启用共享文件夹功能。取而代之,你应该使用 `ADD` 命令添加修改。 50 | 51 | 下面是 "homepage" 开发容器的 Dockerfile 文件,它被我用于开发个人维基。这个容器继承自 "devbase" 容器,这个例子演示了基础容器的重用和共享文件夹的使用。 52 | 53 | ```docker 54 | FROM vidarh/devbase 55 | WORKDIR /home/vidarh/src/repos/homepage 56 | ENTRYPOINT bin/homepage web 57 | ``` 58 | *(备注:我本应给 "devbase" 容器加上标签)* 59 | 60 | 下面是我的个人博客开发容器的 Dockerfile 文件: 61 | 62 | ```docker 63 | FROM vidarh/devbase 64 | 65 | WORKDIR / 66 | USER root 67 | 68 | # For Graphivz integration 69 | RUN apt-get update 70 | RUN apt-get -y install graphviz xsltproc imagemagick 71 | 72 | USER vidarh 73 | WORKDIR /home/vidarh/src/repos/hokstad-com 74 | ENTRYPOINT bundle exec rackup -p 8080 75 | ``` 76 | 77 | 因为这些容器可直接从公共仓库拉取,且基于可重用的基础容器构建,当容器依赖发生变更时,我们可以快速重建容器,这对于避免引入未文档化的依赖(未写入 Dockerfile 中的依赖)也非常重要。 78 | 79 | 即使我们的基础系统已经非常轻量,却仍有提升的空间:容器中的大部分功能将不会被使用。 Docker 采用写时复制(copy-on-write)层技术,也许不会造成太大资源开销,但这意味着我们没能构建一个最小依赖系统,也无法将被攻击和出错的风险降到最低。 80 | 81 | ## 3. 开发工具专用容器 82 | 83 | 本节内容对于通过 `ssh` 等工具进行开发的用户(而非 IDE 用户)比较有价值,最吸引我的是这种模式可以将代码编辑和测试执行(test-executing)从应用中完全分离出来。 84 | 85 | 一直以来,令我非常困扰的问题是:开发、生产环境和开发工具的依赖经常混在一起。这个问题很难真正解决,在开发过程中我们总会不经意的安装一些未文档化的依赖(比如:通过 `apt-get` 安装 strace / tcpdump / emacs 这些最终不被需要的工具时,不可避免会安装大量的依赖)。过去,我必须花上数周时间 "逆向工程(reverse engineering)" 这些应用的依赖,因为它们已经和我的开发、测试甚至生产环境混在一起。 86 | 87 | 定期的测试部署(test-deployments)可以帮助我们解决这个问题,但这并不完美。结合以上两种模式,我找到了从根本解决问题的办法。我首先创建一个专用容器,安装 emacs 等必需的开发工具,然后通过笔记本安装的 "autossh" 工具,保持在专用容器的会话里。再借助共享文件夹功能,就可以在专用容器直接编辑开发容器中的代码。考虑到专用容器只会影响调试和开发,有时我会在其中直接试用一些工具(遇到好用的就加入 Dockerfile 中,没用的下次重建容器的时候会自动消失)。下面是开发工具专用容器的 Dockerfile 文件: 88 | 89 | ```docker 90 | FROM vidarh/devbase 91 | RUN apt-get update 92 | RUN apt-get -y install openssh-server emacs23-nox htop screen 93 | 94 | # For debugging 95 | RUN apt-get -y install sudo wget curl telnet tcpdump 96 | 97 | # For 32-bit experiments 98 | RUN apt-get -y install gcc-multilib 99 | 100 | # Man pages and "most" viewer: 101 | RUN apt-get install -y man most 102 | 103 | RUN mkdir /var/run/sshd 104 | ENTRYPOINT /usr/sbin/sshd -D 105 | 106 | VOLUME ["/home"] 107 | EXPOSE 22 108 | EXPOSE 8080 109 | ``` 110 | 111 | 利用共享文件夹 "/home" ,通过 `ssh` 可以方便的使用专用容器,我会慢慢加强专用容器的功能,但目前来看,它已经能满足我的需求。 112 | 113 | ## 4. 针对不同环境的测试容器 114 | 115 | 我喜欢 Docker 的另一个理由是可以轻松的在不同环境的容器中测试代码。举个栗子,我升级了 [Ruby compiler project](http://www.hokstad.com/compiler) 项目,使其支持 Ruby 1.9 ,但对 Ruby 1.8 的支持情况未知。此时,我仅需一个小小的 Dockerfile ,便可在 Ruby 1.8 下对项目进行测试。 116 | 117 | ```docker 118 | FROM vidarh/devbase 119 | RUN apt-get update 120 | RUN apt-get -y install ruby1.8 git ruby1.8-dev 121 | ``` 122 | 123 | 当然也可以使用 `rbenv` 这类工具,但当需要大量的系统包时这些工具并不省心(和曾经的 Ruby 一样痛苦)。有了 Docker 容器,当我需要不同的运行环境时,运行 `docker run` 命令即可,且不局限于 Ruby 这种自带版本切换工具的环境。完整的虚拟机也能胜任这项任务,但相比之下,Docker 消耗的时间少很多。 124 | 125 | ## 5. 构建专用容器 126 | 127 | 虽然大多数时候我使用解释性语言编程,但依然有些时候,我需要执行昂贵的构建(build)操作。举个栗子,用于运行 Ruby 应用的 "bundler" 工具在更新 Rubygems 依赖关系时,如果应用很大,会消耗大量时间。并且,我们经常需要安装一些运行时不需要的依赖,比如:安装 gems 时有时会引入一些依赖的系统包,而这些包通常没有文档化(未写入 Dockerfile 中),非常容易引入整个 build-essential 包及其依赖。同时,因为宿主环境和部署容器的环境可能并不兼容,我也不想在宿主环境中构建(build)应用。 128 | 129 | 解决方案之一是创建构建(build)专用容器,如果专用容器和应用容器的依赖环境不同,就单独创建 Dockerfile 文件;如果专用容器和应用容器的依赖环境一致,则可复用应用容器的 Dockerfile 文件,使其运行所期望的构建(build)命令。下面是构建(build)专用容器的 Dockerfile 文件。 130 | 131 | ```docker 132 | FROM myapp 133 | RUN apt-get update 134 | RUN apt-get install -y build-essential [assorted dev packages for libraries] 135 | VOLUME ["/build"] 136 | WORKDIR /build 137 | CMD ["bundler", "install","--path","vendor","--standalone"] 138 | ``` 139 | 140 | 运行构建(build)专用容器,并挂载源代码目录到构建(build)专用容器的 "/build" 目录。这样我就可以将构建流程及其依赖封装在两个或多个容器中,最终实现应用构建(build)或者打包(packaging)的解偶。 141 | 142 | *(我经常检查整条构建流水线,为了能够100%重现最终的打包步骤,需要检查构建的每一个环节,确保流水线能精确的完成整个构建过程)* 143 | 144 | ## 6. 安装专用容器 145 | 146 | 这个方法虽非本人原创,但却着实值得一提。 [nsenter and docker-enter tools](https://github.com/jpetazzo/nsenter) 是一款优秀的工具, 它出自流行的 `curl [some url you have no control over] | bash` 模式,它也提供了一个构建专用容器,但却更进一步。其在 Dockerfile 的最后部分下载并构建了一个合适版本的 nsenter (未对下载文件做完整性检查)。 147 | 148 | ```docker 149 | ADD installer /installer 150 | CMD /installer 151 | ``` 152 | 153 | 其中 "installer" 文件如下所示: 154 | 155 | ```bash 156 | #!/bin/sh 157 | if mountpoint -q /target; then 158 | echo "Installing nsenter to /target" 159 | cp /nsenter /target 160 | echo "Installing docker-enter to /target" 161 | cp /docker-enter /target 162 | else 163 | echo "/target is not a mountpoint." 164 | echo "You can either:" 165 | echo "- re-run this container with -v /usr/local/bin:/target" 166 | echo "- extract the nsenter binary (located at /nsenter)" 167 | fi 168 | ``` 169 | 170 | 这种情况下,虽然恶意攻击者可能利用权限问题攻击该容器,但攻击面却非常有限。本节的方法更多时候是为了避免 [开发者在安装脚本时不经意执行危险操作](https://github.com/MrMEEE/bumblebee-Old-and-abbandoned/issues/123) 。我喜欢这种方法,希望通过它能够减少大家对 `curl [something] | bash` 的厌恶(即时杯具发生,也仅会影响专用容器)。 171 | 172 | ## 7. 默认服务专用容器 173 | 174 | 当我认真对待一个 app 时,我会快速准备合适的容器,用于安装数据库等服务。对于项目,这一系列经过优化调整的 "基本" 容器都是无价的。与运行 `docker run [some-app-name]` 创建容器或者直接从 Docker Hub 拉取容器相比,我更倾向于先审核它们,搞清楚它们如何处理数据,然后优化调整容器,最后保存在自己的容器库中。下面是 Beanstalkd 的 Dockerfile 文件: 175 | 176 | ```docker 177 | FROM debian:wheezy 178 | ENV DEBIAN_FRONTEND noninteractive 179 | RUN apt-get -q update 180 | RUN apt-get -y install build-essential 181 | ADD http://github.com/kr/beanstalkd/archive/v1.9.tar.gz /tmp/ 182 | RUN cd /tmp && tar zxvf v1.9.tar.gz 183 | RUN cd /tmp/beanstalkd-1.9/ && make 184 | RUN cp /tmp/beanstalkd-1.9/beanstalkd /usr/local/bin/ 185 | EXPOSE 11300 186 | CMD ["/usr/local/bin/beanstalkd","-n"] 187 | ``` 188 | *(对比这个栗子,我有个更加复杂的 postgres 容器,其中包括持久化的数据和各种配置文件)* 189 | 190 | 我的目标是当需要 memcached ,postgres 和 beanstalk 时,只需运行三条 `docker run` 命令,三个根据我的宿主环境和个人偏好优化的容器将被创建并运行,这样建立“标准”基础设施组件只需一分钟。 191 | 192 | ## 8. 基础设施 / 胶水容器 193 | 194 | 上文介绍了很多用于开发环境的容器(这意味着讨论生产环境需要更多的篇幅),但还是漏了一类容器——胶水容器。胶水容器用于将各种环境粘合成一个整体,目前为止,这一领域还有待研究,这里我先举个栗子: 195 | 196 | 为了更加方便的访问容器,我构建了一个小小的 haproxy 容器,并在家用DNS服务器上添加一条A记录指向该容器,设置 iptable 防火墙使得 haproxy 容器可以正常访问,下面是对应的 Dockerfile 文件: 197 | 198 | ```docker 199 | FROM debian:wheezy 200 | ADD wheezy-backports.list /etc/apt/sources.list.d/ 201 | RUN apt-get update 202 | RUN apt-get -y install haproxy 203 | ADD haproxy.cfg /etc/haproxy/haproxy.cfg 204 | CMD ["haproxy", "-db", "-f", "/etc/haproxy/haproxy.cfg"] 205 | EXPOSE 80 206 | EXPOSE 443 207 | ``` 208 | 209 | 首先由脚本生成 `haproxy.cfg` 文件,然后根据 `docker ps` 的输出生成后端(backend)部分: 210 | 211 | ``` 212 | backend test 213 | acl authok http_auth(adminusers) 214 | http-request auth realm Hokstad if !authok 215 | server s1 192.168.0.44:8084 216 | ``` 217 | 218 | 前端(frontend)定义中关于 acls 和 use_backend 部分的声明,可将来自 `[hostname].mydomain` 的请求转发到 `backend test` 后端。 219 | 220 | 如果希望优雅一些,可以部署类似 [AirBnB's Synapse](https://github.com/airbnb/synapse) 这样的服务发现系统,其提供的功能选项远超我的需求。以上这些容器已经能够满足我对家用环境的多数需求,但工作中,我还在不断的推出各种新容器,这些容器使得真实应用的部署轻而易举,就仿佛拥有一套私有云系统。 221 | 222 | 原文:[Eight Docker Development Patterns](http://www.hokstad.com/docker/patterns) -------------------------------------------------------------------------------- /docs/利用 Vagrant 部署 CoreOS 和 Docker 容器(译).md: -------------------------------------------------------------------------------- 1 | Title: 利用 Vagrant 部署 CoreOS 和 Docker 容器(译) 2 | date: 2014-10-30 3 | url: getting-started-with-coreos-and-docker-using-vagrant 4 | tags: docker, coreos, vagrant, etcd, fleet 5 | toc: yes 6 | status: draft 7 | 8 | 这是关于 [CoreOS](https://coreos.com/) 和 [Docker](https://docker.com/) 系列文中的第一篇,这篇文章主要介绍以下内容: 9 | 10 | 1. CoreOS 是什么? 11 | 2. 如何在 [Vagrant](https://www.vagrantup.com/) 虚拟机上运行 CoreOS 系统? 12 | 3. 如何使用 [fleet](https://github.com/coreos/fleet) 向 CoreOS 集群提交任务(比如:运行 Docker 容器)和执行基本管理任务? 13 | 14 | 这一系列文章基本阐明了 fleet 介绍视频的内容: [利用 fleet 部署 Docker 容器集群](https://coreos.com/blog/cluster-level-container-orchestration/) ,只是用 Vagrant 代替了 [Amazon EC2](https://aws.amazon.com/cn/ec2/) 。 15 | 16 | ## 一、为什么选择 CoreOS ? 17 | 18 | 我喜欢 Docker ,它非常有趣。但如果你希望在生产环境中大规模使用 Docker ,还需要施加一些魔法。我们希望不构建 [PaaS](https://zh.wikipedia.org/zh/%E5%B9%B3%E5%8F%B0%E5%8D%B3%E6%9C%8D%E5%8A%A1) 平台,也能充分释放 Docker 的潜力。在集群系统上运行服务,需要一个好的解决方案来解决服务发现、配置管理和部署等问题,单靠 Docker 无法完成这些。 19 | 20 | 市场上已有很多基于 Docker 的有趣项目,比如: [Dokku](https://github.com/progrium/dokku) , [Flynn](https://flynn.io/) 和 [Deis](http://deis.io/) , CoreOS 也算其中之一。但 CoreOS 并未努力成为另一个 PaaS 平台,它是一个专为大规模集群系统裁剪的 Linux 发行版,选择性吸收了一些 PaaS 平台特性。 21 | 22 | ## 二、CoreOS 是什么? 23 | 24 | 大多数 Linux 发行版自带很多软件包,有些包在服务部署时并不需要。 CoreOS 将不需要的统统裁掉,只保留系统核心,同时支持通过 Docker 按需创建应用容器。 25 | 26 | CoreOS 提供 [etcd](https://github.com/coreos/etcd) (用于服务发现和配置管理的高可用、分布式键值存储服务)和 fleet (协助 etcd 提供分布式初始化服务,集群系统下的 [systemd](http://www.freedesktop.org/wiki/Software/systemd/) )两个工具。有了 CoreOS 和这些工具,就可以对集群系统而非单个主机执行所希望的操作。通常 CoreOS , etcd 和 fleet 不会制造麻烦(参考 [Apache ZooKeeper](http://zookeeper.apache.org/) , [doozerd](https://github.com/ha/doozerd) 和 [Substack's Fleet](https://github.com/substack/fleet) 文档),有了 systemd 和 Docker 后,它们更加配合默契,已然是一个整体。 27 | 28 | ## 三、具体部署步骤 29 | 30 | 以下步骤均在 OS X 环境下进行, Linux 下步骤雷同。 31 | 32 | ### 1. 安装依赖软件 33 | 34 | 1. [VirtualBox](https://www.virtualbox.org/) - 使用版本 4.3.10 35 | 2. Vagrant - 使用版本 1.5.2 36 | 3. fleetctl - fleet 的命令行客户端 37 | 38 | 首先,直接下载解压安装 fleetctl 客户端: 39 | 40 | ```bash 41 | $ wget https://github.com/coreos/fleet/releases/download/v0.3.2/fleet-v0.3.2-darwin-amd64.zip 42 | $ unzip fleet-v0.3.2-darwin-amd64.zip 43 | $ sudo cp fleet-v0.3.2-darwin-amd64/fleetctl /usr/local/bin/ 44 | ``` 45 | 46 | 或者通过 homebrew 安装: 47 | 48 | ```bash 49 | $ brew update 50 | $ brew install fleetctl 51 | ``` 52 | 53 | > **注意**:考虑到 CoreOS 正在快速开发中, fleetctl 可能随时更新, CoreOS 及其 Vagrantfile 也是如此。使用之前,请确认这些工具和 CoreOS 版本保持一致。 54 | 55 | ### 2. 克隆 CoreOS 的 Vagrantfile 仓库 56 | 57 | ```bash 58 | $ git clone https://github.com/coreos/coreos-vagrant/ 59 | $ cd coreos-vagrant 60 | $ DISCOVERY_TOKEN=`curl -s https://discovery.etcd.io/new` 61 | $ perl -p -e "s@#discovery: https://discovery.etcd.io/@discovery:$DISCOVERY_TOKEN@g" user-data.sample > user-data 62 | $ export NUM_INSTANCES=1 63 | ``` 64 | 65 | 将 `user-data.sample` 重命名为 `user-data` ,为让 Vagrantfile 启动 CoreOS 中的 etcd 和 fleet 工具;生成一个 discovery token 作为集群的唯一标识,为让所有节点知道自己所属集群。最后一行告诉 Vagrant 共启动多少台虚拟机,默认一台。 66 | 67 | ### 3. 启动 Vagrant 虚拟机 68 | 69 | 启动 Vagrant 虚拟机,并通过 SSH 登入。 70 | 71 | ```bash 72 | $ vagrant up 73 | ``` 74 | 75 | > **Vagrant 小贴士**:执行 `vagrant ssh` 命令登入 Vagrant 虚拟机,执行 `Ctrl-d` 退出当前 SSH 会话,此时虚拟机仍在后台运行,通过 `vagrant ssh` 可重新登入。修改 Vagrantfile 后需要执行 `vagrant reload --provision` 命令重载配置文件并重启虚拟机。执行 `vagrant halt` 命令关闭虚拟机,执行 `vagrant destroy` 命令销毁虚拟机和所有内部数据。希望了解更多 Vagrant 相关知识,执行 `vagrant --help` 命令查看。 76 | 77 | 到此为止,一个基本可用的 CoreOS 虚拟机已准备就绪。 78 | 79 | ### 4. 在 Vagrant 虚拟机上运行基于 CoreOS 的 Docker 容器 80 | 81 | 本节将介绍如何在 CoreOS 虚拟机中远程拉取公共仓库(public registry)里的 Docker 镜像,这里以运行预制的 [dillinger.io](http://dillinger.io/)(一个基于 HTML5 的 Markdown 编辑器)镜像为例。首先在虚拟机中创建 dillinger.io 服务的 systemd unit 文件(告诉 systemd 如何启动和关闭一项服务的配置文件),命名为 `dillinger.service` : 82 | 83 | ```bash 84 | $ cat dillinger.service 85 | [Unit] 86 | Description=dillinger.io 87 | Requires=docker.service 88 | After=docker.service 89 | 90 | [Service] 91 | ExecStart=/usr/bin/docker run -p 3000:8080 dscape/dillinger 92 | ``` 93 | 94 | 这个文件指导 systemd 如何通过 `docker run` 命令启动容器:基于 `dscape/dillinger` 镜像创建容器,绑定容器的 `8080` 端口到宿主(虚拟机)的 `3000` 端口。此外,我们需要创建环境变量,告诉 `fleetctl` 如何通过 SSH 与 虚拟机进行通信,简单测试一下: 95 | 96 | ```bash 97 | $ export FLEETCTL_TUNNEL=127.0.0.1:2222 98 | $ ssh-add ~/.vagrant.d/insecure_private_key 99 | $ fleetctl list-machines 100 | MACHINE IP METADATA 101 | c9f8bd2f... 172.17.8.101 - 102 | ``` 103 | 104 | 然后顺序输入下面的命令(以 `$` 开头的行): 105 | 106 | ```bash 107 | $ fleetctl submit dillinger.service 108 | $ fleetctl list-units 109 | UNIT LOAD ACTIVE SUB DESC MACHINE 110 | dillinger.service - - - dillinger.io - 111 | $ fleetctl start dillinger.service 112 | Job dillinger.service scheduled to c6d23f21.../172.17.8.101 113 | $ fleetctl list-units 114 | UNIT LOAD ACTIVE SUB DESC MACHINE 115 | dillinger.service loaded active running dillinger.io c6d23f21.../172.17.8.101 116 | $ fleetctl journal dillinger.service 117 | -- Logs begin at Sat 2014-04-19 22:45:43 UTC, end at Sat 2014-04-19 22:48:53 UTC. -- 118 | Apr 19 22:47:12 core-01 systemd[1]: Starting dillinger.io... 119 | Apr 19 22:47:12 core-01 systemd[1]: Started dillinger.io. 120 | Apr 19 22:47:12 core-01 docker[3136]: Unable to find image 'dscape/dillinger' locally 121 | Apr 19 22:47:12 core-01 docker[3136]: Pulling repository dscape/dillinger 122 | ``` 123 | 124 | `fleetctl list-units` 命令将列出所有提交过的容器,告诉我们它的状态和集群中所属机器。 `fleetctl journal -f dillinger.service` 命令打印指定容器最近的日志,加上 `-f` 参数后自动刷新日志。如你所见,从远程仓库拉取 Docker 镜像会花费一些时间,等待之余,不妨通过 SSH 登入虚拟机,了解一些诊断工具。 125 | 126 | ```bash 127 | $ vagrant ssh 128 | $ docker ps -a 129 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 130 | 018a1bbbaadd dscape/dillinger:latest /bin/sh -c 'forever 7 seconds ago Up 7 seconds 0.0.0.0:3000->8080/tcp agitated_babbage 131 | $ sudo netstat -tulpn 132 | Active Internet connections (only servers) 133 | Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name 134 | tcp6 0 0 :::22 :::* LISTEN 1/systemd 135 | tcp6 0 0 :::3000 :::* LISTEN 3125/docker 136 | tcp6 0 0 :::7001 :::* LISTEN 3064/etcd 137 | tcp6 0 0 :::4001 :::* LISTEN 3064/etcd 138 | ``` 139 | 140 | `docker ps -a` 命令显示容器已经开始运行,正如上文配置文件:容器的 `8080` 端口映射到虚拟机的 `3000` 端口, `netstat -tulpn` 列出所有正在监听端口的进程(加上 `sudo` 后显示最后一列进程ID和名称),不出所料 Docker 正在监听 `3000` 端口。通过浏览器访问 [http://172.17.8.101:3000](http://172.17.8.101:3000/) ,你会看到 dillinger.io 实例已经运行起来。 141 | 142 | 如果没有正常运行,检查步骤,查看日志,通过 `docker ps` 和 `netstat` 进行彻底排查。如果 `docker ps -a` 什么都没有返回,同时日志也未报错,也许虚拟机仍在下载镜像中。 143 | 144 | ## 四、结束语 145 | 146 | 我们开启了一个运行简单服务的 CoreOS 虚拟机,同时了解了一些简单的管理和诊断工具。你可能希望将其作为一个开发沙箱,在里面折腾 Docker 容器和创建 Docker 镜像。下一篇文章里面,我们将学习利用 etcd 和 fleet 管理集群系统中的多台虚拟机。 147 | 148 | 原文:[Getting Started with CoreOS and Docker using Vagrant](http://lukebond.ghost.io/getting-started-with-coreos-and-docker-using-vagrant/) 149 | -------------------------------------------------------------------------------- /docs/访问 Docker 容器的名字空间.md: -------------------------------------------------------------------------------- 1 | 熟悉 Linux 技术的人都知道,容器只是利用名字空间进行隔离的进程而已,Docker 在容器实现上也是利用了 Linux 自身的技术。 2 | 3 | 有时候,我们需要在宿主机上对容器内进行一些操作,当然,这种绕过 Docker 的操作方式并不推荐。 4 | 5 | 如果你使用的是比较新的 Docker 版本,会尴尬的发现,直接使用系统命令,会无法访问到容器名字空间。 6 | 7 | 8 | 这里,首先介绍下 `ip netns` 系列命令。这些命令负责操作系统中的网络名字空间。 9 | 10 | 首先,我们使用 `add` 命令创建一个临时的网络名字空间 11 | ``` 12 | $ip netns add test 13 | ``` 14 | 然后,使用 `show` 命令来查看系统中的网络名字空间,会看到刚创建的 test 名字空间。 15 | ``` 16 | $ip netns show 17 | test 18 | ``` 19 | 20 | 另外,一个很有用的命令是 `exec`,会在对应名字空间内执行命令。例如 21 | ``` 22 | $ ip netns exec test ifconfig 23 | ``` 24 | 25 | 使用 `del` 命令删除刚创建的 test 名字空间。 26 | ``` 27 | $ip netns del test 28 | ``` 29 | 30 | 接下来运行一个 Docker 容器,例如 31 | 32 | ```sh 33 | $ docker run -it ubuntu 34 | ``` 35 | 36 | 再次执行 `ip netns show`命令。很遗憾,这里什么输出都没有。 37 | 38 | 39 | 原因在于,Docker 启动容器后仍然会以进程号创建新的名字空间,但在较新的版本里面,默认删除了系统中的名字空间信息文件。 40 | 41 | 网络名字空间文件位于 /var/run/netns 下面,比如我们之前创建的 test 名字空间,则在这个目录下有一个 test 文件。诸如 netns 类似的系统命令依靠这些文件才能获得名字空间的信息。 42 | 43 | 在容器启动后,查看这个目录,会发现什么都没有。 44 | 45 | OK,那让我们手动重建它。 46 | 47 | 首先,使用下面的命令查看容器进程信息,比如这里的1234。 48 | ``` 49 | $ docker inspect --format='{{ .State.Pid }}' $container_id 50 | 1234 51 | ``` 52 | 53 | 接下来,在 /proc 目录(保存进程的所有相关信息)下,把对应的网络名字空间文件链接到 /var/run/netns 下面 54 | 55 | ``` 56 | $ ln -s proc/1234/ns/net /var/run/netns/ 57 | ``` 58 | 59 | 然后,就可以通过正常的系统命令来查看或访问容器的名字空间了。例如 60 | 61 | ``` 62 | $ip netns show 63 | 1234 64 | $ ip netns exec 1234 ifconfig eth0 172.16.0.10/16 65 | ... 66 | ``` --------------------------------------------------------------------------------