[
  {
    "path": ".gitignore",
    "content": "lesson-05/data\n*/memo.txt\n*/README.md\n.vagrant/\n*/scripts/"
  },
  {
    "path": "LICENSE",
    "content": "CC0 1.0 Universal\n\nStatement of Purpose\n\nThe laws of most jurisdictions throughout the world automatically confer\nexclusive Copyright and Related Rights (defined below) upon the creator and\nsubsequent owner(s) (each and all, an \"owner\") of an original work of\nauthorship and/or a database (each, a \"Work\").\n\nCertain owners wish to permanently relinquish those rights to a Work for the\npurpose of contributing to a commons of creative, cultural and scientific\nworks (\"Commons\") that the public can reliably and without fear of later\nclaims of infringement build upon, modify, incorporate in other works, reuse\nand redistribute as freely as possible in any form whatsoever and for any\npurposes, including without limitation commercial purposes. These owners may\ncontribute to the Commons to promote the ideal of a free culture and the\nfurther production of creative, cultural and scientific works, or to gain\nreputation or greater distribution for their Work in part through the use and\nefforts of others.\n\nFor these and/or other purposes and motivations, and without any expectation\nof additional consideration or compensation, the person associating CC0 with a\nWork (the \"Affirmer\"), to the extent that he or she is an owner of Copyright\nand Related Rights in the Work, voluntarily elects to apply CC0 to the Work\nand publicly distribute the Work under its terms, with knowledge of his or her\nCopyright and Related Rights in the Work and the meaning and intended legal\neffect of CC0 on those rights.\n\n1. Copyright and Related Rights. A Work made available under CC0 may be\nprotected by copyright and related or neighboring rights (\"Copyright and\nRelated Rights\"). Copyright and Related Rights include, but are not limited\nto, the following:\n\n  i. the right to reproduce, adapt, distribute, perform, display, communicate,\n  and translate a Work;\n\n  ii. moral rights retained by the original author(s) and/or performer(s);\n\n  iii. publicity and privacy rights pertaining to a person's image or likeness\n  depicted in a Work;\n\n  iv. rights protecting against unfair competition in regards to a Work,\n  subject to the limitations in paragraph 4(a), below;\n\n  v. rights protecting the extraction, dissemination, use and reuse of data in\n  a Work;\n\n  vi. database rights (such as those arising under Directive 96/9/EC of the\n  European Parliament and of the Council of 11 March 1996 on the legal\n  protection of databases, and under any national implementation thereof,\n  including any amended or successor version of such directive); and\n\n  vii. other similar, equivalent or corresponding rights throughout the world\n  based on applicable law or treaty, and any national implementations thereof.\n\n2. Waiver. To the greatest extent permitted by, but not in contravention of,\napplicable law, Affirmer hereby overtly, fully, permanently, irrevocably and\nunconditionally waives, abandons, and surrenders all of Affirmer's Copyright\nand Related Rights and associated claims and causes of action, whether now\nknown or unknown (including existing as well as future claims and causes of\naction), in the Work (i) in all territories worldwide, (ii) for the maximum\nduration provided by applicable law or treaty (including future time\nextensions), (iii) in any current or future medium and for any number of\ncopies, and (iv) for any purpose whatsoever, including without limitation\ncommercial, advertising or promotional purposes (the \"Waiver\"). Affirmer makes\nthe Waiver for the benefit of each member of the public at large and to the\ndetriment of Affirmer's heirs and successors, fully intending that such Waiver\nshall not be subject to revocation, rescission, cancellation, termination, or\nany other legal or equitable action to disrupt the quiet enjoyment of the Work\nby the public as contemplated by Affirmer's express Statement of Purpose.\n\n3. Public License Fallback. Should any part of the Waiver for any reason be\njudged legally invalid or ineffective under applicable law, then the Waiver\nshall be preserved to the maximum extent permitted taking into account\nAffirmer's express Statement of Purpose. In addition, to the extent the Waiver\nis so judged Affirmer hereby grants to each affected person a royalty-free,\nnon transferable, non sublicensable, non exclusive, irrevocable and\nunconditional license to exercise Affirmer's Copyright and Related Rights in\nthe Work (i) in all territories worldwide, (ii) for the maximum duration\nprovided by applicable law or treaty (including future time extensions), (iii)\nin any current or future medium and for any number of copies, and (iv) for any\npurpose whatsoever, including without limitation commercial, advertising or\npromotional purposes (the \"License\"). The License shall be deemed effective as\nof the date CC0 was applied by Affirmer to the Work. Should any part of the\nLicense for any reason be judged legally invalid or ineffective under\napplicable law, such partial invalidity or ineffectiveness shall not\ninvalidate the remainder of the License, and in such case Affirmer hereby\naffirms that he or she will not (i) exercise any of his or her remaining\nCopyright and Related Rights in the Work or (ii) assert any associated claims\nand causes of action with respect to the Work, in either case contrary to\nAffirmer's express Statement of Purpose.\n\n4. Limitations and Disclaimers.\n\n  a. No trademark or patent rights held by Affirmer are waived, abandoned,\n  surrendered, licensed or otherwise affected by this document.\n\n  b. Affirmer offers the Work as-is and makes no representations or warranties\n  of any kind concerning the Work, express, implied, statutory or otherwise,\n  including without limitation warranties of title, merchantability, fitness\n  for a particular purpose, non infringement, or the absence of latent or\n  other defects, accuracy, or the present or absence of errors, whether or not\n  discoverable, all to the greatest extent permissible under applicable law.\n\n  c. Affirmer disclaims responsibility for clearing rights of other persons\n  that may apply to the Work or any use thereof, including without limitation\n  any person's Copyright and Related Rights in the Work. Further, Affirmer\n  disclaims responsibility for obtaining any necessary consents, permissions\n  or other rights required for any use of the Work.\n\n  d. Affirmer understands and acknowledges that Creative Commons is not a\n  party to this document and has no duty or obligation with respect to this\n  CC0 or use of the Work.\n\nFor more information, please see\n<http://creativecommons.org/publicdomain/zero/1.0/>\n\n"
  },
  {
    "path": "README.md",
    "content": "# docker101\n“Docker入门与实践”课程讲义及参考\n\n# 目录结构\n\n每个文件夹内容如下\n\n- keynote.md：课程讲义\n- README.md：一些额外的备注、参考，以及实验脚本、步骤。\n- 实验源文件等其他文件\n\n# 注意事项\n\n- 请不要拷贝keynote.md里的命令，可能会有格式问题（Markdown的list格式）\n- 请拷贝README.md中的命令\n\n\n# 有问题？\n\n[请提issue](https://github.com/liubin/docker101/issues)\n\n# 全部视频连接\n\n* [Docker基本概念](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2720)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker1.jpg)\n* [Docker实现原理](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2721)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker2.jpg)\n* [Docker组件介绍](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2722)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker3.jpg)\n* [Docker实操环境介绍](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2723)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker4.jpg)\n* [什么是Docker容器](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2724)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker5.jpg)\n* [深入Docker容器](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2725)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker6.jpg)\n* [Docker容器的生命周期管理](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2726)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker7.jpg)\n* [认识Docker镜像](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2727)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker8.jpg)\n* [手工构建Docker镜像](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2728)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker9.jpg)\n* [使用Dockerfile构建Ruby镜像](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2729)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker10.jpg)\n* [Dockerfile指令说明](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2730)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker11.jpg)\n* [构建私有镜像服务器](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2731)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker12.jpg)\n* [为私有镜像服务添加Basic认证...](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2732)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker13.jpg)\n* [为私有镜像服务添加Token认证...](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2733)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker14.jpg)\n* [Docker Hub和自动构建](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2734)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker15.jpg)\n* [Docker容器连接](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2735)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker16.jpg)\n* [创建和使用数据卷](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2736)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker17.jpg)\n* [使用数据卷容器](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2737)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker18.jpg)\n* [使用Docker Compose](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2738)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker19.jpg)\n* [Docker Compose配置文件解说](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2739)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker20.jpg)\n* [初识Docker Machine](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2740)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker21.jpg)\n* [使用Docker Machine创建云主机...](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2741)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker22.jpg)\n* [Docker Machine命令详解](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2742)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker23.jpg)\n* [Swarm简介](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2743)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker24.jpg)\n* [Swarm调度策略和过滤机制](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2744)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker25.jpg)\n* [Docker网络基础](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2745)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker26.jpg)\n* [Docker网络模式](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2746)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker27.jpg)\n* [灵雀云简介](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2747)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker28.jpg)\n* [使用灵雀云命令行工具](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2748)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker29.jpg)\n* [基于Docker进行持续集成](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2749)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker30.jpg)\n* [网络、存储和PaaS平台](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2750)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker31.jpg)\n* [容器OS和容器标准化](http://www.kaikeba.com/kkb/kaikeba/content_video.html?vId=2751)\n![](http://video.kk8.cdn.bj.xs3cnc.com/2c/i/covers/Docker32.jpg)\n"
  },
  {
    "path": "Vagrantfile",
    "content": "# -*- mode: ruby -*-\n# vi: set ft=ruby :\n\n# All Vagrant configuration is done below. The \"2\" in Vagrant.configure\n# configures the configuration version (we support older styles for\n# backwards compatibility). Please don't change it unless you know what\n# you're doing.\nVagrant.configure(2) do |config|\n  # The most common configuration options are documented and commented below.\n  # For a complete reference, please see the online documentation at\n  # https://docs.vagrantup.com.\n\n  # Every Vagrant development environment requires a box. You can search for\n  # boxes at https://atlas.hashicorp.com/search.\n  config.vm.box = \"chef/centos-7.0\"\n\n  # Disable automatic box update checking. If you disable this, then\n  # boxes will only be checked for updates when the user runs\n  # `vagrant box outdated`. This is not recommended.\n  # config.vm.box_check_update = false\n\n  # Create a forwarded port mapping which allows access to a specific port\n  # within the machine from a port on the host machine. In the example below,\n  # accessing \"localhost:8080\" will access port 80 on the guest machine.\n  config.vm.network \"forwarded_port\", guest: 4567, host: 4567\n  config.vm.network \"forwarded_port\", guest: 8080, host: 8080\n  config.vm.network \"forwarded_port\", guest: 5000, host: 5000\n  config.vm.network \"forwarded_port\", guest: 80, host: 80\n  config.vm.network \"forwarded_port\", guest: 3000, host: 3000\n\n\n  # Create a private network, which allows host-only access to the machine\n  # using a specific IP.\n  config.vm.network :private_network, ip: \"192.168.0.66\"\n\n  config.vm.hostname = \"docker101vm\"\n  # Create a public network, which generally matched to bridged network.\n  # Bridged networks make the machine appear as another physical device on\n  # your network.\n  # config.vm.network \"public_network\"\n\n  # Share an additional folder to the guest VM. The first argument is\n  # the path on the host to the actual folder. The second argument is\n  # the path on the guest to mount the folder. And the optional third\n  # argument is a set of non-required options.\n  # config.vm.synced_folder \"../data\", \"/vagrant_data\"\n\n  # Provider-specific configuration so you can fine-tune various\n  # backing providers for Vagrant. These expose provider-specific options.\n  # Example for VirtualBox:\n  #\n  config.vm.provider \"virtualbox\" do |vb|\n  #   # Display the VirtualBox GUI when booting the machine\n  #   vb.gui = true\n  #\n  #   # Customize the amount of memory on the VM:\n    vb.memory = \"1024\"\n    vb.customize ['modifyvm', :id, '--nicpromisc1', 'allow-all']\n  end\n  #\n  # View the documentation for the provider you are using for more\n  # information on available options.\n\n  # Define a Vagrant Push strategy for pushing to Atlas. Other push strategies\n  # such as FTP and Heroku are also available. See the documentation at\n  # https://docs.vagrantup.com/v2/push/atlas.html for more information.\n  # config.push.define \"atlas\" do |push|\n  #   push.app = \"YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME\"\n  # end\n\n  # Enable provisioning with a shell script. Additional provisioners such as\n  # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the\n  # documentation for more information about their specific syntax and use.\n  # config.vm.provision \"shell\", inline: <<-SHELL\n  #   sudo apt-get update\n  #   sudo apt-get install -y apache2\n  # SHELL\nend\n"
  },
  {
    "path": "lesson-01/keynote.md",
    "content": "# Docker入门与实践\n\n刘斌，软件工程师@Alauda\n2015年8月\n\n\n# 课程简介\n\n- 目的\n- 对象\n- 内容\n\n# 对象用户\n\n- Linux\n- Git（GitHub）\n\n# 参考资料\n\n- 官方文档（https://docs.docker.com/）\n- 《第一本Docker书》\n\n# 什么是Docker\n\n- Build, Ship, Run\n- An open platform\n- For distributed applications\n- For developers and sysadmins\n- https://www.docker.com\n- https://www.github.com/docker/docker\n\n# 什么是Docker\n\n- 开放平台\n- 容器技术\n- 交付标准\n- 开发流程\n\n# Docker产生背景\n\n- 云计算技术\n- 软件架构\n- 积累的问题\n\n# 云计算技术\n\n- 虚拟化技术\n- IaaS(AWS)\n- PaaS(Heroku)\n- 网络技术（SDN/Open vSwitch/Overlay网络/隧道技术）\n\n# 观点\n\n- An EC2 instance is not a server—it’s a building block.\n- Re:Invent，Amazon’s CTO, Werner Vogels\n\n# 软件架构\n\n- SOA\n- 微服务\n- 12-Factor App\n- Blue-green Deployment\n- Golden Image\n\n# 积累问题\n\n- 依赖地狱和一致环境\n- Hardware\n- OS\n- Library(Version etc.)\n- Rails(3/4),Ruby(1.8/1.9/2.0/2.1)\n\n\n# 12-Factor App\n\n- Codebase\n- Dependencies\n- Config\n- Build, release, run\n- Processes\n- Port binding\n- Dev/prod parity\n- Logs\n\n# Docker的解决方案\n\n- 集装箱思想\n- 标准化（大小、运输方式等，接口统一）\n- 隔离（互不干扰、影响）\n\n# Docker的解决方案\n\n![](./images/docker-solution.png)\n\n# 什么是容器？\n\n- 一组进程在独自的OS环境\n- 独立文件内容\n- 独立网络环境（hostname，IP地址等）\n- CPU、内存分配\n\n# 只是容器？\n\n- Docker（2013）\n- lmctfy（2013）\n- LXC（2008）\n- RHEL OpenVZ（2005）\n- Solaris Zones（2004）\n- FreeBSD jail（2000）\n- chroot（????）\n\n# 只是容器？\n\n- chroot（1979/1982）\n\n# 为什么Docker吸引人\n\n- 简单\n- 轻量\n- 隔离\n- 移植性\n- 以应用为中心\n- 版本化\n- 重用\n- Immutable\n\n# 简单一句话\n\n- 从阳春白雪，到下里巴人\n- 从专业运维、SA专家，到前端、设计师\n\n# 和虚拟机相比\n\n![](./images/docker-vs-vm.png)\n\n# 和虚拟机相比\n\n- 实现原理\n- 启动时间\n- 可启动实例数量\n- overhead\n- 安全性（隔离）\n- 磁盘空间\n\n# Docker实现原理\n\n- 核心Linux内核功能\n- Control Groups（cgroups）\n- Namespace\n- iptables\n- Union File System\n\n# 安全相关内核功能\n\n- Kernel Capability\n- 对进程持有的特权进行细粒度管理的机制\n- 系统时间，内核模块，硬件设备\n- SELinux(Security-Enhanced Linux/RedHat系Linux)\n- Apparmor(简单/Debian/Ubuntu)\n\n# cgroups\n\n- Control groups\n- 按资源划分等级的不同组内\n- 共享硬件\n- 对资源进行限制\n- 记账\n- 伪文件系统的实现方式\n\n# cgroups\n\n- blkio： 块设备读写限制（Read <= N bytes/sec）\n- cpu： 对CPU调度器的限制\n- cpuset： 多核下对CPU访问的控制\n- cpuacct: CPU accounting controller\n- devices： 对设备的控制\n- freezer：处理的暂停和恢复\n- memory： 控制内存资源的使用\n- net_cls： 使用等级识别符（classid）标记网络数据包，可允许 Linux 流量控制程序（tc）识别从具体 cgroups 中生成的数据包。\n- net_prio： 对不同网络接口通信的优先级别的设置\n\n\n# Namespaces\n\n- pid： 进程（PID）隔离（2.6.24）\n- net： 网络隔离（2.6.26）\n- ipc： IPC隔离，POSIX消息队列，共享内存（2.6.19）\n- mnt： 挂载点隔离（2.4.19）\n- uts： hostname，NIS域名（UTS: Unix Timesharing System）（2.6.19）\n- user： 用户隔离（3.8）\n\n# Docker适用场景\n\n- 开发\n- 测试\n- 部署\n- CI/CD\n- PaaS/CaaS\n- 只有想不到，没有做不到\n- 还有人用来装Eclipse呢\n\n# Docker将会给这些领域带来影响\n\n- Software Development\n- Deploy & Delivery\n- DevOps\n\n# Docker带来的收益\n\n- 快速交付（交付标准）\n- 轻松部署\n- 快速缩、扩容\n- 提高资源利用率（高密度、满负荷）\n- 提升软件工程师满意度\n\n# Docker历史\n\n- 优秀的产品背后都有一家伟大的公司\n- docCloud（YCombinator），2013年1月内部项目\n- 2013年3月，在PyCon US首次公开\n- 2013/3/27 Docker 0.1\n- 2014/6 Docker 1.0\n- 几乎每月一个版本\n- 2015年8月，Docker 1.8发布\n- 2014.7 C轮融资4000万美元\n- 2015.4 D轮融资9500万美元\n\n# 支持平台\n\n- Linux\n- Boot2Docker（Windows 、 OS X）\n- Windows native\n\n# Docker 组件\n\n- Docker Engine 或 “Docker”\n- 创建和运行Docker容器，运行平台。\n- Docker Hub\n- 托管的Registry，镜像托管服务，无需安装，只需要注册一个账号。\n- Docker Registry\n- 开源的Docker镜像分发服务（存储、下载）。\n\n\n# Docker 组件\n\n- Docker Machine\n- 本地或者云端自动容器环境provisioning工具。\n- Docker Compose\n- 多容器应用管理\n- Docker Swarm\n- 容器集群和调度管理工具\n\n# Docker 组件\n\n- Kitematic\n- 桌面GUI管理程序\n- Docker Toolbox\n- 替代Boot2Docker\n\n# Docker 组件\n\n- Docker Trusted Registry(DTR)\n- 私有专用镜像Registry。\n- Docker Subscription\n- Docker订购，增值服务；\n- 在整个部署、分发的生命周期提供帮助\n- 包括DTR\n- 部署到公有或者私有云\n\n# 我们不会讲\n\n- Docker ToolBox/Kitematic： 有了本课程基础，应对Kitematic应该小事一桩\n- DTR： 我们会讲Registry\n- Docker Subscription：\n- 1. 我们会讲 Registry\n- 2. 都花钱买Subscription了，就享受服务吧\n\n# Docker Engine架构\n\n- C/S结构\n- Remote API（RESTful）\n- TLS支持\n\n![](./images/docker-arch.png)\n\n# Docker in Linux\n\n![](./images/docker-daemon-cli.png)\n\n# Libcontainer\n\n- Container format\n- Execution driver\n- 将cgroups，Namespace，Union FS集成到一起使用\n\n![](./images/docker-libcontainer-lxc.png)\n\n# Docker Engine核心概念\n\n- Docker镜像（image）\n- Docker容器（containers）\n- Docker Registry\n\n# 镜像\n\n- 文件系统\n- 只读、静态\n- 层（Layer）\n- 父子关系（Parent Image）\n- 基础镜像（Base Image）\n- ID（64字符，256bit存储）\n\n# 容器 - Container\n\n- 创建、运行和退出\n- ID（和镜像ID类似）\n\n![](./images/docker-filesystem.png)\n\n# Registry\n\n- 托管镜像仓库（repositories of images）\n- Registry API\n- Docker Hub和私有Registry\n- 码头上的仓库\n\n# 课程演习环境\n\n- Vagrant\n- CentOS 7\n- Docker 1.7.1\n- 灵雀云（alauda.cn）\n\n# Docker For Non-Linux\n\n- Boot2Docker\n- Toolbox\n\n# Docker in Non-Linux\n\n![](./images/docker-in-osx.png)\n\n# Docker Toolbox (Docker 1.8)\n\n- Docker Client\n- Docker Machine\n- Docker Compose (Mac only)\n- Docker Kitematic\n- VirtualBox\n\n![](./images/docker-toolbox-logo.png)\n\n# VirtualBox和Vagrant\n\n- 虚拟机\n- 虚拟机管理软件\n- hashicorp\n- Serf/Consul/Packer等工具\n\n# Vagrant\n\n- vagrant init chef/centos-7.0\n- vagrant up\n- vagrant ssh\n\n# Vagrant\n\n- 下载centos7镜像：http://pan.baidu.com/s/1kT7u5oF\n- vagrant box add chef/centos-7.0 opscode_centos-7.0_chef-provisionerless.box\n- 执行上一页命令\n\n# 不必一切从头开始\n\n- git clone https://github.com/liubin/docker101\n\n# Vagrantfile\n\n- box\n- forwarded_port\n- synced_folder\n\n# 安装Docker\n\n- 64位Linux\n- 内核3.10\n\n# 安装Docker\n\n- $ sudo yum update\n- $ curl -sSL https://get.docker.com/ | sh\n- $ sudo systemctl enable docker\n- $ sudo systemctl start docker\n- $ sudo docker -v\n- Docker version 1.8.1, build d12ea79\n\n# 设置镜像加速\n\n- 灵雀云（https://console.alauda.cn）\n- --registry-mirror=http://liubin.m.alauda.cn\n\n# 答疑\n\n- https://github.com/liubin/docker101\n- Alauda社区\n\n# 课后作业\n\n- 浏览官方文档\n- 安装Docker\n- 注册alauda.cn账户\n\n"
  },
  {
    "path": "lesson-02/keynote.md",
    "content": "# Docker入门与实践\n\nLesson-02 运行Docker容器\n刘斌@Alauda\n2015年8月\n\n# 本节概要\n\n- docker命令的两个角色\n- 理解容器构造\n- 管理容器生命周期\n- docker run命令的用法\n\n# docker命令\n\n- 一个命令，两个角色\n- daemon: docker daemon\n- client: docker run/ps/rm/images\n- docker -D？\n\n# Docker daemon(Server)\n\n- -H=[]，监听接口（damain socket或者IP/端口）\n- unix:///var/run/docker.sock\n- -H tcp://host:2375\n- --tls=true|false\n- 《第一本Docker书》第8.5节\n- fd： Systemd socket activation\n\n# Docker Daemon参数\n\n- 网络、安全、日志等\n- -e, --exec-driver=\"native\"\n- -s, --storage-driver=\"\"\n- 存储驱动AUFS/device mapper/btrfs/zfs/overlay\n\n# Docker execdriver\n\n- libcontainer\n- lxc\n\n![](../lesson-01/images/docker-libcontainer-lxc.png)\n\n# Docker daemon(Server)\n\n- $ sudo systemctl status docker\n- $ sudo systemctl start docker\n- $ sudo systemctl stop docker\n- $ sudo systemctl restart docker\n- $ sudo systemctl enable docker\n\n# DOCKER_HOST环境变量\n\n- docker -H tcp://0.0.0.0:2375 ps\n- export DOCKER_HOST=\"tcp://0.0.0.0:2375\" && docker ps\n\n# 设置灵雀云加速\n\n```\n[docker101vm]$ sudo vi /lib/systemd/system/docker.service\n\n/usr/bin/docker daemon --registry-mirror=http://liubin.m.alauda.cn -H fd://\n\n[docker101vm]$ sudo systemctl daemon-reload\n```\n\n# 演示 1\n\n- 通过IP地址连接远程Docker\n- docker -H tcp://0.0.0.0:2375 pull ubuntu\n\n# 启动容器\n\n- docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]\n\n# 演示 2\n\n- 启动我们的第2个容器\n- $ sudo docker run -it centos bash\n\n# 演示 2：容器内部\n\n- [root@e757c235c60c /]#\n- hostname\n- ip addr show eth0\n- mount\n- ps -ef\n- mount\n- exit\n- docker ps -a\n\n# 演示 3：容器/镜像 ID\n\n- 64位\n- 容器\n- 镜像/镜像层\n- 长形UUID（64位）\n- 短形UUID(12位)\n- 1位？\n\n# 容器命名\n\n- name：cocky_curie（scientists and hackers）\n- docker run --name\n\n# Tips： 如何获得容器ID？\n\n- cid=$(docker run --name name1 -d -P --cidfile=/tmp/cid.lock training/webapp python app.py)\n- docker stop $cid\n- --cidfile=\"some/path\"\n\n# 容器的生命周期\n\n- 创建、启动（docker create/run/restart）\n- 停止（stop、kill区别？）\n- 销毁（rm）\n\n# 前台容器和后台容器\n\n- Foreground/Detached (-d)\n- sudo docker run -it centos bash\n\n# 前台容器\n\n- 启动容器内进程，并将当前控制台attach到该进程的标准输入、输出和错误。\n- -t：分配一个伪终端（TTY）\n- -i：保持STDIN打开\n- -it：交互式控制台（Shell）\n\n# 后台容器\n\n```bash\ndocker run --name web -d -P training/webapp python app.py\ndocker port web\n```\n\n# 后台容器\n\n- -d： 后台运行，无前台输入输出交互\n- -P： 暴露所有端口\n- -p： 精确指定端口\n\n# docker attach\n\n- attach 到一个Detached的容器上\n\n\n# docker attach\n\n- docker attach [OPTIONS] CONTAINER\n- --no-stdin=false\n- --sig-proxy=true\n- detach： CTRL-p CTRL-q (for a quiet exit)\n- detach： CTRL-c if --sig-proxy == false\n- SIGINT： CTRL-c if --sig-proxy == true（默认）\n\n\n# docker attach\n\n- 演示5\n\n# stop/kill\n\n- stop，SIGTERM,超过-t(10s)则SIGKILL\n- kill，SIGKILL\n- kill -s, --signal=\"SIGKILL\"\n\n# 常用容器命令\n\n- docker stop/kill\n- docker ps -a|-n --no-trunc\n- docker rm\n\n# Tips 自动删除停止的容器\n\n- docker run --rm 自动清除容器\n- 和选项 -d 不兼容\n\n# 容器网络设置\n\n- --dns=[]\n- --mac-address=\"\"\n- --add-host=\"\"\n- --net=\"bridge\"\n\n# --net选项\n\n- bridge\n- none\n- container:<name|id>\n- host\n\n# Tips 如何修改容器内的/etc/hosts文件？\n\n```bash\ndocker run -it --add-host db-server:10.10.0.100\n```\n\n# 演示\n\n- 使用host模式\n- 检查网络设置\n- /etc/hosts\n- /etc/resolve.conf\n- /etc/hostname\n- --add-host测试\n\n\n# docker events\n\n- docker events [OPTIONS]\n- create, destroy, die, export, kill, oom, pause, restart, start, stop, unpause\n- untag, delete\n- 指定时间段和过滤器\n- 演示6\n\n# 指定时间条件\n\n- --since=\"\"\n- --until=\"\"\n- docker events --since 1378216169\n- docker events --since '2013-09-03'\n- docker events --since '2013-09-03T15:49:29'\n\n# 指定filter\n\n- -f / --filter\n- container\n- event\n- image\n- AND / OR\n\n# 指定filter\n\n- docker events -f 'event=stop'\n- docker events -f 'image=ubuntu:14.04'\n- docker events -f 'container=xx' -f 'container=yy'\n- docker events -f 'container=xx' -f 'event=stop'\n\n# restart机制\n\n- none\n- on-failure[:max-retries]\n- always\n- 每次重试间隔时间都翻倍，直到stop或rm -f\n- 演示7\n\n# 其他一些docker命令\n\n- docker rename/top/cp\n- docker pause CONTAINER\n- docker unpause CONTAINER\n- docker diff\n\n# docker create\n\n- docker create [OPTIONS] IMAGE [COMMAND] [ARG...]\n- then docker start\n- 状态：created.\n\n# docker create 用武之地\n\n```bash\ndocker create -v /data --name data centos\n240633dfbb98128fa77473d3d9018f6123b99c454b3251427ae190a7d951ad57\ndocker run --rm --volumes-from data centos ls -la /data\ntotal 8\ndrwxr-xr-x  2 root root 4096 Dec  5 04:10 .\ndrwxr-xr-x 48 root root 4096 Dec  5 04:11 ..\n```\n\n# 常用选项\n\n- 在镜像中指令有关\n- -v\n- -e\n- -p\n- -P\n\n# ENTRYPOINT\n\n- --entrypoint=\"\"\n- docker inspect centos | jq \".[0].Config.Entrypoint\"\n\n# EXPOSE\n\n- Dockerfile里唯一对网络设置选项\n- -P或-p\n- -p 5000\n- -p 6000:6000\n- -p 127.0.0.1:7000:7000\n- -p 127.0.0.1::7000\n\n# ENV\n\n- 预设： HOME/HOSTNAME/PATH/TERM\n- --link\n- -e \"deep=purple\"\n\n# VOLUME\n\n- -v=[] [host-dir:]container-dir[:rw|ro]\n- --volumes-from=\"\"\n\n# 演示8\n\n- 见 README.md\n\n# USER\n\n- 默认为root\n- -u=\"\": Username or UID\n\n# WORKDIR\n\n- -w=\"\"\n\n\n# Logging驱动\n\n- 容器可以指定logging驱动\n- --log-driver=VALUE\n- none\n- json-file（默认，docker logs可用）\n- syslog\n- journald\n- gelf： Graylog Extended Log Format (GELF)\n- fluentd\n\n# 演示9\n\n- 查看log\n- /var/lib/docker/containers\n- 容器停止后的log\n- 见 README.md\n\n# 对容器进行资源限制-Memory\n\n- -m, --memory=\"\": 格式 <number><optional unit>（单位为b/k/m/g）\n- --memory-swap=\"\": 内存总量限制（memory+swap，单位同上）\n- --oom-kill-disable=true|false\n\n# 对容器进行资源限制-Memory\n\n- -m 300M --memory-swap -1\n- -m 300M （--memory-swap 600M）\n- 全部内存 = 2 * m，swap = m\n- -m 300M --memory-swap 1G\n\n# 对容器进行资源限制-Memory\n\n- -m 100M --oom-kill-disable\n- --oom-kill-disable <- 危险行为\n\n# 对容器进行资源限制-CPU\n\n- -c, --cpu-shares=0: CPU shares （相对权重）\n- --cpu-period=0: 限制 CPU完全公平调度程序 (Completely Fair Scheduler)时间\n- --cpu-quota=0: 限制 CPU CFS用量\n- --cpuset-cpus=\"\": 可用CPU的核(0-3, 0,1)\n- --cpuset-mems=\"\": 可利用的Memory节点 (0-3, 0,1)，NUMA系统可用\n- 非一致性内存访问 NUMA（Non-Uniform Memory Access Architecture）\n- NUMA = SMP（对称多处理） + MPP（大规模并行处理）\n- 每个节点都有独立的CPU+内存，甚至I/O\n\n# 对容器进行资源限制-CPU share\n\n- 所有容器的默认CPU周期（cycles）权重为1024\n- 通过-c 或 --cpu-shares 设置为大于2的值\n- 多个容器按比例分配CPU\n\n# 对容器进行资源限制-CPU quota\n\n- 选项 --cpu-quota 用来对容器的CPU使用做出限制\n- 默认值0表示可以使用100%的CPU\n\n# 对容器进行资源限制-CPU period\n\n- 默认完全公平调度程序CFS（Completely Fair Scheduler）周期为100ms\n- 通过--cpu-period 可以限制容器的CPU使用\n- 单位：microseconds，百万分之一，微秒\n- 通常和--cpu-quota一起工作\n- --cpu-period=50000 --cpu-quota=25000 -> 50% CPU\n\n# 对容器进行资源限制-CPU set\n\n- 指定运行所在CPU\n- --cpuset-cpus=\"1,3\" ...\n- --cpuset-cpus=\"0-2\" ...\n\n# 对容器进行资源限制-Block I/O\n\n- --blkio-weight\n- 设置I/O权重，取值范围为10~1000\n- 容器默认I/O权重为500\n- $ docker run --blkio-weight 300\n\n# 和Namespace相关的一些参数\n\n- PID\n- UTS\n- IPC\n\n# PID\n\n- --pid=\"\"，设置容器的PID namespace\n- --pid=host\n\n# UTS\n\n- --uts=\"\"，设置UTS namespace\n- 'host'\n- 容器名随host而变\n- 在容器中修改host的主机名\n\n# IPC\n\n- --ipc=\"\"，设置容器的IPC模式\n- container:<name|id>\n- host\n- 演示10\n\n# Linux capabilities\n\n- 默认Docker容器没有特权“unprivileged”\n- --privileged 允许容器访问所有设备（device）\n- 或修改AppArmor/SELinux的配置\n- 精细控制（--cap-add/--cap-drop）\n- --device\n- --lxc-conf\n- docker run --device=/dev/snd:/dev/snd ...\n\n# Linux capabilities示例\n\n- SETPCAP： 修改进程\n- SYS_MODULE： 加载/卸载内核模块\n- SYS_ADMIN：系统管理\n- SYS_TIME： 修改系统时间\n- NET_ADMIN： 网络管理操作\n- KILL： 跳过权限发送signal\n- SETGID/SETUID：设置UID/GID\n- SYSLOG：使用SYSLOG\n- CHOWN：修改属主\n\n\n# 课后作业\n\n- 下载centos仓库\n- docker run -it centos bash\n- docker ps -a\n- docker rm\n- 尝试docker run的各种选项\n\n\n\n\n\n"
  },
  {
    "path": "lesson-03/keynote.md",
    "content": "# Docker入门与实践\n\nLesson-03 理解Docker镜像\n刘斌@Alauda\n2015年8月\n\n# 本节概要\n\n- 镜像构造\n- 管理镜像\n- 手工构建镜像\n- Docker存储原理\n\n# 什么是Docker镜像\n\n- 容器的模板\n- 分层\n- manifest(json) + layers\n- layer: tar包\n\n![](../lesson-01/images/docker-filesystem.png)\n\n# 分层的优势\n\n- 轻量（磁盘空间）\n- 缓存，提高构建速度\n\n# Repository\n\n- 存放一组镜像的仓库\n- 有一个名字\n- 一个镜像可以属于多个仓库\n- docker commit\n- docker build -t\n- docker tag\n\n# 仓库名称\n\n- [registry[:port]/][user_name/]repository_name:version_tag\n- 默认index.docker.io:80\n\n\n# 拉取和推送镜像\n\n- docker search\n- docker pull\n- docker push\n\n# 查看Docker镜像\n\n- docker images\n- REPO/TAG/ID\n- docker history\n- docker inspect\n- tag\n- docker rmi\n\n# 演示1\n\n- docker login\n- docker pull\n- docker tag\n- docker push\n\n# 构建镜像\n\n- 必要性\n- 方式：commit，Dockerfile，从0开始\n- 优缺点：Dockerfile > commit> 从0开始\n\n# 通过docker commit命令构建镜像\n\n- docker run -it base bash\n- # yum update && yum install xxx && exit\n- docker commit \n\n# 演示2\n\n- 创建nginx镜像\n\n# docker commit 参数\n\n- -m --message\n- -a --author\n- -c --changes\n\n# commit -c可覆盖参数\n\n- CMD、ENTRYPOINT\n- ENV\n- EXPOSE\n- ONBUILD\n- USER\n- VOLUME\n- WORKDIR\n\n# 共享镜像\n\n- 镜像存储\n- 官方\n- 免费+收费\n- 或私有Registry\n\n# 拷贝到其他机器\n\n- Docker iamge = tar文件\n- export/import\n- save/load\n\n# export/import\n\n- export：整个mount，将rootfs打成一个tar包\n- import：tar包解包而已\n- 镜像层级关系和metadata丢失\n- 不能共享层文件，占用大量磁盘空间\n- 能导入物理机或者虚拟机的rootfs\n\n# save/load\n\n- 按镜像层分别打tar包\n- 一层层mount，打包\n- 先打base\n- mount下一层，打包差分\n- 记录metadata\n- 将结果再打成一个tar包\n\n# 演示3\n\n- save导出镜像\n- 解压查看分层\n\n# Docker存储引擎\n\n- CoW\n- AUFS\n- Device Mapper\n- BTRFS\n- overlay(fs)\n- VFS\n- ZFS\n\n# CoW\n\n- Copy on Write\n- Copy only (when) Write\n- Memory（并发编程中犹如内存管理的GC）\n- Storage\n\n# AUFS\n\n- Advanced（Another） Union FS\n- Ubuntu/Debian\n- 没进内核主线\n- dotCloud从2008年就开始用\n- 适合高密度的类PaaS场景\n\n# AUFS原理\n\n- 由多个分支按一定顺序组合\n- 每个只是一个普通文件夹\n- 若干只读分支和一个读写分支（顶层）\n\n# AUFS原理-读写文件\n\n- 读取时从顶层开始查找文件\n- 找到则打开\n- 写入时如果在顶层找到目标文件，则打开\n- 否则继续向下找\n- 如果找到，则拷贝到顶层，开始写入\n- 找不到则在顶层创建文件并写入\n\n# AUFS原理-删除文件\n\n- 创建一个whiteout文件表示删除\n\n# 演示4\n\n- 见README.md\n\n# AUFS优点\n\n- 成熟度以及和Docker的融合性\n- Debian/Ubuntu 内核默认支持\n- mount()调用快，因此创建容器速度快\n- 启动n个容器，只会从磁盘加载一次\n\n# AUFS缺点\n\n- Read/write操作几乎无性能损失\n- open()有时候会很慢：\n- 1. 文件太大（log，数据库文件）\n- 2. 层级太深\n\n\n# BTRFS\n\n- Butter FS,Better FS？\n- B-tree file system，以大规模存储位目标\n- Oracle 2007\n- 受ZFS影响\n- 支持快照、CoW和回滚\n- CentOS 7.1可用，preview\n\n# BTRFS\n\n- 文件系统级别的CoW\n- 数据分为chunk，可存储meta和data\n- diff快\n- 基于subvolume + snapshot\n- 要求Docker运行于BTRFS之上（/var/lib/docker）\n- Docker相关代码好像只有几百行\n\n# overlay\n\n- 内核3.18\n- 类似AUFS，不过只有两个分支\n- 但是每个分支也可以是overlay的\n- 性能优于AUFS\n- 现在需要在ext4上运行\n\n# VFS\n\n- 没有CoW，每次拷贝\n- 不需要内核特性支持\n- 浪费空间\n- 慢\n- 适宜移植到其他平台\n\n# ZFS\n\n- Solaris（现Oracle）\n- 2005年发布\n- Zettabyte File System\n- 1 ZiB（泽字节） = 1,099,511,627,776 (1024的4次方)GiB\n- 也被移植到包括Linux在内的其他OS上\n\n# Device Mapper\n\n- RAID（dm-raid）\n- 设备加密（dm-crypt）\n- 快照（snapshots）\n- 延迟写入（dm-delay）\n- Docker未使用LVS\n- Docker : thin-provisioning + snapshot\n\n# thin provisioning\n\n- dm-thin/dm-thinp\n- 数据存放在两个文件，data和metadata\n- data 也叫做block pool（block：默认64KB，最大1G）\n- 从存储池（block池）分配逻辑设备\n- dm-thin将逻辑设备mount成容器的文件系统\n- 每次发生CoW（写入），才去分配block\n- metadata保存着快照中虚拟位移和pool中物理位移的对应关系\n\n## thin provisioning\n\n- Docker镜像和容器都有自己的block设备\n- 默认data大小100GB（meta为2G）\n- 镜像大小10GB\n- 可以分配大于10个的容器\n- 如果一个block没有被写入，则不会真正分配物理磁盘\n- 可超卖\n\n# Device Mapper\n\n![](./images/dm-block-mapping.png)\n\n图片来源： http://www.school.ctc-g.co.jp/columns/nakai/nakai59.html\n\n# Device Mapper\n\n![](./images/dm-snapshot.png)\n\n图片来源： http://www.school.ctc-g.co.jp/columns/nakai/nakai59.html\n\n\n# Device Mapper\n\n![](./images/dm-remap.png)\n\n\n# Device Mapper\n\n- 块级别而不是文件级别的CoW\n- 随时对镜像（->容器）或者容器（->镜像）做快照\n- 不依赖于文件系统（在FS之下）\n\n# Device Mapper相关命令\n\n- docker info\n- losetup\n- 设备名： docker-MAJ:MIN-INO\n- MAJ： block major\n- MIN： block minor\n- INO： inode number\n\n# 演示5\n\n- 见README.md\n\n\n# Device Mapper优点\n\n- 容器自己的block设备\n- 位于fs下层，支持多种文件系统类型\n- 可共享block\n\n# Device Mapper缺点\n\n- 不能直接查看layer之间的diff\n- docker diff慢\n- data和metadata基于sparse文件\n- loop device而不是真正的/dev设备\n- 每启动1次容器，都需要从磁盘加载一次\n- 崩溃报告较多\n\n# 结论\n\n- 类PaaS高密度\n- AUFS（或overlay）\n- 频繁写大文件？\n- Device Mapper或者BTRFS\n\n# 课后作业\n\n- docker pull\n- docker history|inspect\n- docker images/rmi\n- docker commit\n- docker push\n\n\n"
  },
  {
    "path": "lesson-04/app/Dockerfile",
    "content": "FROM liubin/ruby:2.2.2\n\n\nMAINTAINER bin liu <liubin0329@gmail.com>\n\nLABEL version=\"0.0.1\" lang=\"myapp\"\n\nCOPY app.rb /app/app.rb\n\nWORKDIR /app\n\nRUN gem sources --remove https://rubygems.org/ \\\n  && gem sources -a http://ruby.taobao.org/\n\nRUN gem install sinatra\n\nEXPOSE 4567\n\nCMD [\"ruby\", \"app.rb\"]\n\n"
  },
  {
    "path": "lesson-04/app/app.rb",
    "content": "require 'sinatra'\n\nget '/' do\n  'Hello world!'\nend\n\nset :bind, '0.0.0.0'\n"
  },
  {
    "path": "lesson-04/dockerfiles/Dockerfile",
    "content": "FROM centos:7 \n\nMAINTAINER bin liu <liubin0329@gmail.com>\n\n\n# 单独添加一个文件\nADD files/file1.txt /dir1\nADD files/file2.txt /dir2/\n\n# 添加多个文件\n# Step 4 : ADD files/* /dir3\n# When using ADD with more than one source file, the destination must be a directory and end with a /\n# ADD files/* /dir3\n\nADD files/* /dir4/\n\n\n# src为文件夹\nADD files /dir5\nADD files /dir6/\nADD files/ /dir7/\n\n# 添加URL文件（带文件名）\nADD https://raw.githubusercontent.com/docker/docker/master/Dockerfile /url1\n\nADD https://raw.githubusercontent.com/docker/docker/master/Dockerfile /url2/\n\n\n# 添加URL文件（不带文件名）\nADD https://github.com/ /url3\n\n# Step 8 : ADD https://github.com/ /url4/\n# Downloading 17.63 kB\n# cannot determine filename from url: https://github.com/\n\n# ADD https://github.com/ /url4/\n\n\n\n"
  },
  {
    "path": "lesson-04/dockerfiles/Dockerfile-entrypoint-shell",
    "content": "FROM centos:7 \n\nMAINTAINER bin liu <liubin0329@gmail.com>\n\nENTRYPOINT top -b"
  },
  {
    "path": "lesson-04/files/file1.txt",
    "content": "a\n"
  },
  {
    "path": "lesson-04/files/file2.txt",
    "content": "b\n"
  },
  {
    "path": "lesson-04/keynote.md",
    "content": "# Docker入门与实践\n\nLesson-04 使用Dockerfile构建镜像\n刘斌@Alauda\n2015年8月\n\n# 本节概要\n\n- 掌握构建镜像的方式\n- docker build命令\n- Dockerfile语法\n\n# 构建镜像的方式\n\n- docker commit\n- Dockerfile\n- Packer类\n\n# Dockerfile是什么\n\n- 构建镜像的说明书\n- DSL语法\n- docker inspect\n\n# 为什么用Dockerfile\n\n- 版本控制（追踪和回滚）\n- 公开透明\n- 一定程度的可重现\n\n# 使用Dockerfile构建的流程\n\n- 编写Dockerfile\n- 执行docker build命令\n\n# 演示\n\n- 构建Ruby镜像\n\n\n# docker build命令\n\n- docker build -t liubin/someimg[:sometag] path\n- path: 本地路径、远程URL和 \"-\"\n\n# 从STDIN接收压缩数据\n\n- docker build - < context.tar.gz\n- bzip2/gzip/xz\n\n# 构建环境（Build Context）\n\n- 包含Dockerfile的文件夹下的所有内容\n- ADD file\n\n# 构建环境支持git仓库\n\n- git clone --depth 1 --recursive\n- 还能指定git仓库的分支和目录\n- https://somegit.com/repo.git#fa3424fa:path1\n\n\n# Dockerfile指令格式\n\n- 不区分大小写，指令习惯大写\n- 按顺序读取\n- 以#开头的为注释\n\n# Dockerfile指令格式\n\n```bash\n# Comment\nINSTRUCTION arguments\n```\n\n# ENV变量\n\n```bash\nENV foo /bar\nWORKDIR ${foo}   # WORKDIR /bar\nADD . $foo       # ADD . /bar\n```\n\n# 可以使用ENV变量的指令\n\n- ADD/COPY\n- WORKDIR\n- EXPOSE\n- VOLUME\n\n# cache\n\n- 缓存加快速度\n- --no-cache\n\n# 也能限制build过程使用的资源\n\n- -m\n- -c\n\n# Tips： Dockerfile只能命名为Dockerfile？\n\n- docker build -f other-docker-file\n\n# .dockerignore\n\n- 等于 .gitignore\n- 指定不需要发送到daemon的文件（夹）\n\n# .dockerignore\n\n```bash\n*/temp*\n*/*/temp*\ntemp?\n*.md\n!LICENSE.md\n```\n\n\n# FROM指令\n\n- FROM <image>\n- FROM <image>:<tag>\n- FROM <image>@<digest>\n\n\n# MAINTAINER指令\n\n- MAINTAINER <name>\n\n# RUN指令\n\n- RUN cmd arg （/bin/sh -c）\n- RUN [\"cmd\", \"arg1\", \"arg2\"] （exec格式）\n- RUN [\"/bin/bash\", \"-c\", \"echo hello\"]\n- exec格式需使用双引号而不是单引号\n\n# 状态修改\n\n- 下载、安装文件\n- 创建目录、文件\n- 拷贝、移动文件\n\n# 状态修改\n\n- cd\n- ls\n- pwd\n\n# 测试\n\n- RUN [ \"echo\", \"$HOME\" ]\n\n# 测试\n\n- RUN [ \"sh\", \"-c\", \"echo\", \"$HOME\" ]\n\n# 建议\n\n- 多条换行写\n- 避免单行的RUN apt-get update\n- 避免类似apt-get upgrade等命令\n\n# 建议\n\n```bash\nRUN apt-get update && apt-get install -y \\\n    package-bar \\\n    package-baz \\\n    package-foo\n```\n\n# LABEL\n\n- 镜像元数据\n- LABEL <key>=<value> <key>=<value> <key>=<value> ...\n- LABEL \"com.example.vendor\"=\"ACME Incorporated\"\n- 继承父镜像标签\n- 建议一行写多个label，节省镜像层\n\n# ENTRYPOINT指令\n\n- ENTRYPOINT command param1 param2 (shell form)\n- ENTRYPOINT [\"cmd\", \"param1\", \"param2\"] (exec form)\n- docker run image some-command\n- 可通过docker run --entrypoint覆盖\n- 最后一条ENTRYPOINT指令有效\n\n# Shell形式\n\n- 忽略命令行参数和CMD指令\n\n# Exec形式\n\n- 不启动shell\n\n# CMD指令\n\n- 指定容器默认启动程序\n- CMD [\"executable\",\"param1\",\"param2\"]\n- CMD [\"param1\",\"param2\"]\n- CMD command param1 param2 (shell form)\n- 只有最后一条CMD指令生效\n\n\n# Dockerfile 常用设计模式\n\n- 必须都用JSON数组格式\n\n# Dockerfile 常用设计模式\n\n```bash\nENTRYPOINT [\"s3cmd\"]\nCMD [\"--help\"]\n\n$ docker run s3cmd\n\n$ docker run s3cmd ls s3://mybucket\n```\n\n# EXPOSE\n\n- 仅是声明\n- 不会自动打开，-p或-P\n- EXPOSE <port> [<port>...]\n\n# ENV\n\n- ENV <key> <value>\n- ENV <key>=<value> ...\n- 继承性\n\n# ENV示例\n\n```bash\nENV myName=\"John Doe\" myDog=Rex\\ The\\ Dog \\\n    myCat=fluffy\nand\n\nENV myName John Doe\nENV myDog Rex The Dog\nENV myCat fluffy\n```\n\n# 减少不必要的ENV\n\n- RUN <key>=<value> <command>\n\n# ADD\n\n- 向镜像添加文件\n\n- ADD <src>... <dest>\n- ADD [\"<src>\",... \"<dest>\"]\n- 文件、文件夹和URL\n\n# <src>\n\n- 文件需要位于 build context下\n- src可包含通配符（filepath.Match）\n- src为URL，文件名可以从URL推导\n- src为文件夹，所有文件夹内容被拷贝\n- 为压缩（gzip/bzip2/xz）文件，将会被解开（tar -x）\n\n# <src>\n\n```bash\nADD hom* /mydir/\nADD hom?.txt /mydir/\n```\n\n# <dest>\n\n- 绝对路径\n- 相对于WORKDIR的路径\n- 新文件（夹）的UID=0，GID=0\n- <src>为URL则新文件属性为600\n- 如果指定了多个src，则dest必须以/结尾（否则出错）\n- 建议dest如果为文件夹，则在后面都加上/\n\n# <dest>\n\n```bash\n# adds \"test\" to `WORKDIR`/aDir/\nADD test aDir/\n```\n\n\n# src为URL\n\n- ADD http://abc.com/somfile /file1\n- ADD http://abc.com/somfile /file2/(somefile)\n- ADD http://abc.com/ /file3\n- ADD http://abc.com/ /file4/  （出错）\n- 建议URL和dest都写明确，不要让Docker去推测\n\n\n# COPY指令\n\n- 和ADD一样\n- COPY <src>... <dest>\n- COPY [\"<src>\",... \"<dest>\"]\n\n# ADD还是COPY？\n\n- 推荐COPY\n- 没有URL和自动解压\n- 减少不确定性\n\n- 不同类型的文件单独拷贝（最大效果利用缓存）\n- 手工下载文件后删除（减小镜像尺寸）\n\n- 尽量将全部操作都通过Dockerfile展现\n\n\n# VOLUME\n\n- VOLUME [\"/data\"]\n- VOLUME /var/log\n- VOLUME /var/log /var/db\n\n\n\n# VOLUME测试\n\n```bash\nFROM ubuntu\nRUN mkdir /myvol\nRUN echo \"hello world\" > /myvol/greeting\nVOLUME /myvol\n```\n\n# USER\n\n- USER name or UID\n- 影响RUN/CMD/ENTRYPOINT\n- RUN groupadd -r postgres && useradd -r -g postgres postgres\n- UID/GID不能保证可重现性，可显示指定\n- 默认为root\n\n# USER\n\n```bash\nUSER user\nUSER user:group\nUSER uid\nUSER uid:gid\nUSER user:gid\nUSER uid:group\n```\n\n# WORKDIR\n\n- WORKDIR /path/to/workdir\n- 影响后续RUN/CMD/ENTRYPOINT/COPY/ADD指令\n- 可多次使用\n\n\n# 小测试\n\n```bash\nWORKDIR /a\nWORKDIR b\nWORKDIR c\nRUN pwd\n# pwd命令的结果？\n```\n\n# 小测试\n\n- 结果是：\n- /a/b/c\n\n\n# 小测试\n\n```bash\nENV DIRPATH /path\nWORKDIR $DIRPATH/$DIRNAME\nRUN pwd\n# pwd命令的结果？\n```\n\n# 小测试\n\n- 结果是：\n- /path/$DIRNAME\n- 只能替换Dockerfile设置的env环境变量\n\n# WORKDIR使用建议\n\n- 建议多使用绝对路径\n- 使用WORKDIR替换\"cd ..\"\n\n# ONBUILD指令\n\n- ONBUILD [INSTRUCTION]\n- 子镜像构建触发器，不遗传，不能嵌套\n- 在FROM中执行\n- 不能通过ONBUILD执行FROM和MAINTAINER指令\n- 就像在衍生镜像的FROM指令后执行\n\n\n# 能通过docker run覆盖的镜像参数\n\n- Dockerfile的设置可覆盖\n- FROM/MAINTAINER/RUN/ADD\n- CMD/ENTRYPOINT/EXPOSE/ENV/VOLUME/USER/WORKDIR\n\n# CMD\n\n- docker run -it cnetos:7 bash\n\n# ENTRYPOINT\n\n- --entrypoint=\"\"\n\n# EXPOSE\n\n- Dockerfile里唯一对网络设置选项\n- -P或-p\n- -p containerPort\n- -p hostPort:containerPort\n- -p ip:hostPort:containerPort\n- -p ip::containerPort\n\n\n# ENV\n\n- 预设： HOME/HOSTNAME/PATH/TERM\n- --link\n- -e \"deep=purple\"\n\n# VOLUME\n\n- -v=[] [host-dir:]container-dir[:rw|ro]\n- --volumes-from=\"\"\n\n# USER\n\n- 默认为root\n- -u=\"\": Username or UID\n\n# WORKDIR\n\n- -w=\"\"\n\n\n# 最佳实践\n\n- 使用.dockerignore文件\n- 减少层数\n- 最小安装\n- 注意build cache（apt-get -y update问题）\n\n# 课后作业\n\n- 基于centos:7构建自己的语言栈\n- COPY\n- WORKDIR/ENV\n- EXEC/CMD\n"
  },
  {
    "path": "lesson-04/ruby/Dockerfile",
    "content": "FROM centos:7 \n\nMAINTAINER bin liu <liubin0329@gmail.com>\n\nLABEL version=\"2.2.2\" lang=\"ruby\"\n\nENV RUBY_MAJOR 2.2\nENV RUBY_VERSION 2.2.2\n\nRUN yum install -y wget tar gcc g++ make automake autoconf curl-devel openssl-devel zlib-devel httpd-devel apr-devel apr-util-devel sqlite-devel\n\nRUN cd /tmp \\\n    && wget http://cache.ruby-lang.org/pub/ruby/2.2/ruby-2.2.2.tar.gz \\\n    && tar zxvf ruby-2.2.2.tar.gz \\\n    && cd ruby-2.2.2 \\\n    && autoconf \\\n    && ./configure --disable-install-doc \\\n    && make \\\n    && make install \\\n    && rm -rf /tmp/ruby-2.2.2*\n\n# skip installing gem documentation\nRUN echo -e 'install: --no-document\\nupdate: --no-document' >> \"$HOME/.gemrc\"\n\nENV GEM_HOME /usr/local/bundle\nENV PATH $GEM_HOME/bin:$PATH\n\nENV BUNDLER_VERSION 1.10.6\n\nRUN gem install bundler --version \"$BUNDLER_VERSION\" \\\n\t&& bundle config --global path \"$GEM_HOME\" \\\n\t&& bundle config --global bin \"$GEM_HOME/bin\"\n\n# don't create \".bundle\" in all our apps\nENV BUNDLE_APP_CONFIG $GEM_HOME\n\nCMD [ \"irb\" ]\n\n"
  },
  {
    "path": "lesson-05/auth/domain.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFizCCA3OgAwIBAgIJANxRQ7S8qVmEMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV\nBAYTAkNOMRAwDgYDVQQHDAdCZWlqaW5nMRwwGgYDVQQKDBNEZWZhdWx0IENvbXBh\nbnkgTHRkMR0wGwYDVQQDDBRwcml2YXRlLXJlZ2lzdHJ5LmNvbTAeFw0xNTA4MDkw\nNTQ4MTVaFw0xNjA4MDgwNTQ4MTVaMFwxCzAJBgNVBAYTAkNOMRAwDgYDVQQHDAdC\nZWlqaW5nMRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMR0wGwYDVQQDDBRw\ncml2YXRlLXJlZ2lzdHJ5LmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC\nggIBAMAbN0bWP+UARipgLCVtddOzZl6i00mKnQoW2BD9VhkyvWW2Kqz0zN305IE8\nJYoQv8ZI2WJULAfJ7PXqsxAATx7n9K2QBodjtP8xJPPHOEEKW9pg+Nux9Xefz48P\nw/oBURoV4dyRhaz86ySbqbEdaPPUojti8vsNfCpbEawGWgUdVE5fKKQwLaS7dD15\nspC/aB00u61imjuafvEYR2RwMSVVleFF9iS6Jn1MBRaX3l8Q5/knXMAL001aV9tS\nPjd7uK2j1ZJvln2kgneks19fZWWcZ9ASDWsieQ6IlVmYYDUc/kbrZZp2VMri/ntT\nfgeiRGB6lBmhNUPIE2PPUSrK2SX/NmbUfRljnhpJ8qiB1fJIjmpXIoLcbY/+meN/\nTj2sCK4RPa30NNXoK7kmJ93uZQATyiIp+iWbWiztQm5GZhI4s0WPszg71XkHyyRA\nbepFcZNix8ghEJ9OqVqj57fyicAeFY3jiUbRpuo9PiHdFFq8w5teSl4rrb5nQSM1\nBxIFAziUN0xD5jCDWAS8nJ/D3wnqz/d62grAmem7rZLf4z4A1QIFOa9JqFVWUlrn\nyoi3MXpXy6KkGY/xgufS4eRMmOcgkr30w49U2M1ONQEhC847kq/4y/C+b52mUHh+\nNjvlWbRG9z2YABLUPJGjK/6d7wFxedNDX/YsWVqxH57rjGTlAgMBAAGjUDBOMB0G\nA1UdDgQWBBSLZzdcQtcFPgA7Iml3ZUYv91CjzzAfBgNVHSMEGDAWgBSLZzdcQtcF\nPgA7Iml3ZUYv91CjzzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQAh\ngSWxbsW4wbbAKeKH7bokK2tH6wMjN2XIjd5mibYFnuVu4O1zN8mY45kxITsr4GTi\nZhud6Vdj95ZNYEe/tFSkKD4Zcg7AoMw8hDPxsmI2lkd3+D4GzbAJI57Fmet5tCik\nashBQIsnYEVHCNuSyljyUwuslvn8zNLJSSCp+LiZVShCNJ4O7nS+nwxD4Kez95xO\n7iZ+/KLKtWRpNokMQU6sFdqNmmHKf1X3oWal8yIfZ/DnGSnOyRuDA6Se3NpVQKZy\n7eyWQeVX3zouTHF5vmMVGJ3vniIXZgmDZY5B+fQgO1WEdIvqP0iFt+BCMDgECPO4\nXL02vYtaCC/AaWt3upgMCCk8P6rl5PblUUFR7uZVC+zmTrZfXVV4luyJ39siqZdR\nWS5+rg8bi42l4fxNbTAS23aNFw1cS2wqwiwYV7W6+EFNXl6dDm2pZ334sZZFZIHC\nGlvycsVtuggjocuOluccEWPLIyvGjSYghGjcKsLcbNeCNy/yL6rXcu1rydjQPa7T\nb4oAsTLODDWFOKArTh9/eQWgWxoa8sZ+86V+ErYKEfX9Wv3bO+AwfyUUXy1+a/8B\nKXul1RXz91dinQqEUXxCbfoxUdmNr5sWbm/uFlNrCqVi/NrJenmxVQezQhXABfIS\noFs7VISoJeRHzqUxmfq/l2fVS5/Q33fF8ujNm/tExQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "lesson-05/auth/domain.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQDAGzdG1j/lAEYq\nYCwlbXXTs2ZeotNJip0KFtgQ/VYZMr1ltiqs9Mzd9OSBPCWKEL/GSNliVCwHyez1\n6rMQAE8e5/StkAaHY7T/MSTzxzhBClvaYPjbsfV3n8+PD8P6AVEaFeHckYWs/Osk\nm6mxHWjz1KI7YvL7DXwqWxGsBloFHVROXyikMC2ku3Q9ebKQv2gdNLutYpo7mn7x\nGEdkcDElVZXhRfYkuiZ9TAUWl95fEOf5J1zAC9NNWlfbUj43e7ito9WSb5Z9pIJ3\npLNfX2VlnGfQEg1rInkOiJVZmGA1HP5G62WadlTK4v57U34HokRgepQZoTVDyBNj\nz1Eqytkl/zZm1H0ZY54aSfKogdXySI5qVyKC3G2P/pnjf049rAiuET2t9DTV6Cu5\nJifd7mUAE8oiKfolm1os7UJuRmYSOLNFj7M4O9V5B8skQG3qRXGTYsfIIRCfTqla\no+e38onAHhWN44lG0abqPT4h3RRavMObXkpeK62+Z0EjNQcSBQM4lDdMQ+Ywg1gE\nvJyfw98J6s/3etoKwJnpu62S3+M+ANUCBTmvSahVVlJa58qItzF6V8uipBmP8YLn\n0uHkTJjnIJK99MOPVNjNTjUBIQvOO5Kv+Mvwvm+dplB4fjY75Vm0Rvc9mAAS1DyR\noyv+ne8BcXnTQ1/2LFlasR+e64xk5QIDAQABAoICAQCuiUucgVXF4ozdPUl+q8es\nkscEXl0m6Ngq7XxbW0AZXr8zJOH7B+MGGdRuEk5s9TC3n0JaEu16Ghy/hQAxHobE\nJqxn8H3uDknIvUa8cZkLhrTTYN1ZBYNmrvyuFv3QK9gaohz2AAT6mUOum/r9nyHW\nvq6y1AC81ZClDt6sc4zgLriFB/Ht0pP1ohZHMEVrO2wFdP661eYZFxIUTCG5ADG2\noN6usJik37fOiP3qfAqeRsbr2LZtCZFuKxG9gyhh0neE02BcTiPlfUzIFQyfLxX5\nzrOHGI+2cbiY2sEOiOGIABKKLp6+SppZRwk81SuhFe2X1mauLogtUB9FxHsTLP9B\n8PavVE7VglzflgfnQpj5PBm5v7rWO3RB+iXYvrQvucUJZndf6AzyNfFMPRe4Yvga\ny9aKwjy0A8M9lKlgJPaHDGLt1EII0QfzYW2LjwBu+XBVY2id3/8N/ABjfj/Z/7Fo\na2fb66HHSHlS5o9wblT38RU3wm4rDh13OWuRi7f7iUK8nmBi5bIvxDxEb39T4ZYb\nDut8wpbP5fs+4W/tF0uRr+NIyFiBDIAp7JDow1WCSBS9zV4cSdnkUUtN4v3GPYWl\nhX9EfRC+793od7aKY8RQrN5j8CuU43yp4uu+ZbuO6B/uwkJNt7rPQaBM4ZJP6Lb3\nZzUCCfEvqitrEAHneRsQVQKCAQEA8czXRIdp8I5QADK3iziHydkS3Ug4x/G+IMLr\nDc14fMpUvGXaeulWTtFIG9dvWGGPnUzyNNH/u4/AVfSZm29Ny4hvwygkV+QN5oSD\nw9GR2aGmY0ZqruNPjCrM0najO6pEB+hMbpno/oInfmQUPZVSPEhTjRETjAp98v3q\nJcPISWsEmtDGFNmCTo2/N+FWgQxBSL1Rnk68tQMU7e3ldvjdHWEo4/LANbhYmWQ6\nAkULzE1Z/Jd2coGcG+8lPutIu3ullXXoYyjYOz9o1Xgsrg6tKfo9V2S7tjax9w9i\n3GDDleYcMNKHz4Dx3wvn7ogxXtvOiIv+k68k7DrQyPBdBv3CWwKCAQEAy2NKfgax\n0mdh4sW8UbShFq4PJARE3iz4kot7WXyde+Plq7SBOWSzUktwrFRE8Fv05vkeouGa\nIfQLmvM64os69RSbM5RNzaAzZjwIgAh4sW5pWMl01Qm75xSsqwDkFNJwlz515h9o\nlLEm9O2nfujEfCSMlE5DD0hbPW/2deEE/zxtoheewSxgygXLR0+pX/KZ1XhRSHlk\nM3czeU8gA5jV+yaphi/5LEIhSdpQvUlOcVEFvylHhnevRU7EP8p0vNF8vc26ueFY\nkyK8Xb3W/SJwBbqU5yrhv3TpvjfA3xiuEToQauxblwZ4VTgq4c8Ec2QLZt2d3Vus\naVvhuZeM7jCZvwKCAQA4dA/KYyc7z64j7bNmoMMrQDAkU8lV/T3bnkaMyW0ZDZAt\nEEarLbFF45zHS0wmwVhrbFycMm9Xlh9csifu31S1cVxOnx+lGYyZRlURMeuweQpE\n4VrlDBM1cYSymppPwtfxVK4LoImCalbYLnt/SU6S3nwLUnJS3tw7EEdLm+M2KPNB\nRf8JPSMsPfHoFQdCR98yIWld4ZozVM3dIw7Q8ReG1XlbhwCTSj/9SCY3A3HWuDSL\nQb2YzGPrLbFveDVZ+GtXctjX1eBuLMbIGC+uT6TkSRVrQwyEZU61lPUK6NihNcFd\nMLoem0ddQQVcbpXAROd6f9znFBw1vyGh2GSPzk1DAoIBAQCZqXicYp5yopz34gD3\nkgqqwfK6eWc2nK9ouG0HHPk2ouXgpk2DeStqH4kPCdPT7QXIg6q70MrMoD8sYFu6\n0QpII7tmasOleUWcFfsuEDhvhUWeSQY19la6rYoO4Gtxt9RM0Gnu5Qf0XytZnTwQ\ny/e2+z4ixkYwA7C7aB3CzbEizRrffgz5UXgG6f288Ni8nuPOvkpbASvNHmALZNaB\nITV5vKoTsacF4yiXTZP2jq3vOxGmbZ+WXlJTgMEQmPs9tOAT3p0W1sQ+1d2OzWDi\neuQ7z820IVfReJkol6LmaxUH+uBwiAZiwgakC/2KAQgRziI3I3SjyyElsL+HopJd\nWuatAoIBAQClkgNCPqfDP9t12Ku5I0oMAzJWxE7EIrvrbcN+f7Aoiy8ee9kFqtsD\n1d5vuaBPSJKHwJeqTRvbHk+nDvwJiHo+4310oIQWs433nXba0Xq0sojqTR1Sxf1V\nC43uVHiOUun/Fp94d3Gszn6h0fCzmBJ1fkHnDAWO4DlK2v3/7wdyxmx6ZkV6KEDr\n6emAKyxC2Dbp6bunCZn8S8etQGVm5y61HumUICtQN6hMhl2NQXzemgAwq7xYzeE6\nb7D/c9gqyvzqea120N1ymGyAbO4H3E6h4K+y1TQmIqj+dsRD2fCfmrdKWQZhmJ4h\nmiaEM+UDsXXhkccPXCLPgJPHFKOHNRYN\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "lesson-05/auth/htpasswd",
    "content": "testuser:$2y$05$YheaMXycRTDWOckjFx7PlePYSh/gV2hCCZ12E2dFTLb2KJ42LAqoW\n\n"
  },
  {
    "path": "lesson-05/auth/registry.conf",
    "content": "upstream docker-registry {\n  server registry:5000;\n}\n\nserver {\n  listen 443 ssl;\n  server_name private-registry.com;\n\n  # SSL\n  ssl_certificate /etc/nginx/conf.d/domain.crt;\n  ssl_certificate_key /etc/nginx/conf.d/domain.key;\n\n  # disable any limits to avoid HTTP 413 for large image uploads\n  client_max_body_size 0;\n\n  # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486)\n  chunked_transfer_encoding on;\n\n  location /v2/ {\n    # Do not allow connections from docker 1.5 and earlier\n    # docker pre-1.6.0 did not properly set the user agent on ping, catch \"Go *\" user agents\n    if ($http_user_agent ~ \"^(docker\\/1\\.(3|4|5(?!\\.[0-9]-dev))|Go ).*$\" ) {\n      return 404;\n    }\n\n    # To add basic authentication to v2 use auth_basic setting plus add_header\n    auth_basic \"registry.localhost\";\n    auth_basic_user_file /etc/nginx/conf.d/registry.password;\n    add_header 'Docker-Distribution-Api-Version' 'registry/2.0' always;\n\n    proxy_pass                          http://docker-registry;\n    proxy_set_header  Host              $http_host;   # required for docker client's sake\n    proxy_set_header  X-Real-IP         $remote_addr; # pass on real client's IP\n    proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;\n    proxy_set_header  X-Forwarded-Proto $scheme;\n    proxy_read_timeout                  900;\n  }\n}\n"
  },
  {
    "path": "lesson-05/auth/registry.password",
    "content": "testuser:$apr1$SCscCYJd$5zvIZuj9mTOlMyhNlnDNl0\n"
  },
  {
    "path": "lesson-05/certs/domain.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFizCCA3OgAwIBAgIJANxRQ7S8qVmEMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV\nBAYTAkNOMRAwDgYDVQQHDAdCZWlqaW5nMRwwGgYDVQQKDBNEZWZhdWx0IENvbXBh\nbnkgTHRkMR0wGwYDVQQDDBRwcml2YXRlLXJlZ2lzdHJ5LmNvbTAeFw0xNTA4MDkw\nNTQ4MTVaFw0xNjA4MDgwNTQ4MTVaMFwxCzAJBgNVBAYTAkNOMRAwDgYDVQQHDAdC\nZWlqaW5nMRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMR0wGwYDVQQDDBRw\ncml2YXRlLXJlZ2lzdHJ5LmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC\nggIBAMAbN0bWP+UARipgLCVtddOzZl6i00mKnQoW2BD9VhkyvWW2Kqz0zN305IE8\nJYoQv8ZI2WJULAfJ7PXqsxAATx7n9K2QBodjtP8xJPPHOEEKW9pg+Nux9Xefz48P\nw/oBURoV4dyRhaz86ySbqbEdaPPUojti8vsNfCpbEawGWgUdVE5fKKQwLaS7dD15\nspC/aB00u61imjuafvEYR2RwMSVVleFF9iS6Jn1MBRaX3l8Q5/knXMAL001aV9tS\nPjd7uK2j1ZJvln2kgneks19fZWWcZ9ASDWsieQ6IlVmYYDUc/kbrZZp2VMri/ntT\nfgeiRGB6lBmhNUPIE2PPUSrK2SX/NmbUfRljnhpJ8qiB1fJIjmpXIoLcbY/+meN/\nTj2sCK4RPa30NNXoK7kmJ93uZQATyiIp+iWbWiztQm5GZhI4s0WPszg71XkHyyRA\nbepFcZNix8ghEJ9OqVqj57fyicAeFY3jiUbRpuo9PiHdFFq8w5teSl4rrb5nQSM1\nBxIFAziUN0xD5jCDWAS8nJ/D3wnqz/d62grAmem7rZLf4z4A1QIFOa9JqFVWUlrn\nyoi3MXpXy6KkGY/xgufS4eRMmOcgkr30w49U2M1ONQEhC847kq/4y/C+b52mUHh+\nNjvlWbRG9z2YABLUPJGjK/6d7wFxedNDX/YsWVqxH57rjGTlAgMBAAGjUDBOMB0G\nA1UdDgQWBBSLZzdcQtcFPgA7Iml3ZUYv91CjzzAfBgNVHSMEGDAWgBSLZzdcQtcF\nPgA7Iml3ZUYv91CjzzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQAh\ngSWxbsW4wbbAKeKH7bokK2tH6wMjN2XIjd5mibYFnuVu4O1zN8mY45kxITsr4GTi\nZhud6Vdj95ZNYEe/tFSkKD4Zcg7AoMw8hDPxsmI2lkd3+D4GzbAJI57Fmet5tCik\nashBQIsnYEVHCNuSyljyUwuslvn8zNLJSSCp+LiZVShCNJ4O7nS+nwxD4Kez95xO\n7iZ+/KLKtWRpNokMQU6sFdqNmmHKf1X3oWal8yIfZ/DnGSnOyRuDA6Se3NpVQKZy\n7eyWQeVX3zouTHF5vmMVGJ3vniIXZgmDZY5B+fQgO1WEdIvqP0iFt+BCMDgECPO4\nXL02vYtaCC/AaWt3upgMCCk8P6rl5PblUUFR7uZVC+zmTrZfXVV4luyJ39siqZdR\nWS5+rg8bi42l4fxNbTAS23aNFw1cS2wqwiwYV7W6+EFNXl6dDm2pZ334sZZFZIHC\nGlvycsVtuggjocuOluccEWPLIyvGjSYghGjcKsLcbNeCNy/yL6rXcu1rydjQPa7T\nb4oAsTLODDWFOKArTh9/eQWgWxoa8sZ+86V+ErYKEfX9Wv3bO+AwfyUUXy1+a/8B\nKXul1RXz91dinQqEUXxCbfoxUdmNr5sWbm/uFlNrCqVi/NrJenmxVQezQhXABfIS\noFs7VISoJeRHzqUxmfq/l2fVS5/Q33fF8ujNm/tExQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "lesson-05/certs/domain.key",
    "content": "-----BEGIN PRIVATE KEY-----\n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\nmiaEM+UDsXXhkccPXCLPgJPHFKOHNRYN\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "lesson-05/docker-compose.yml",
    "content": "registry:\n  restart: always\n  image: registry:2\n  ports:\n    - 6000:5000\n  environment:\n    REGISTRY_HTTP_TLS_CERTIFICATE: /certs/domain.crt\n    REGISTRY_HTTP_TLS_KEY: /certs/domain.key\n    REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /var/lib/registry\n    REGISTRY_AUTH: htpasswd\n    REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd\n    REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm\n  volumes:\n    - /vagrant/lesson-05/data:/var/lib/registry\n    - /vagrant/lesson-05/certs:/certs\n    - /vagrant/lesson-05/auth:/auth"
  },
  {
    "path": "lesson-05/keynote.md",
    "content": "# Docker入门与实践\n\nLesson-05 构建私有镜像服务器\n刘斌@Alauda\n2015年8月\n\n# 本节概要\n\n- 什么是Registry和Index\n- 部署私有Registry\n- 集成Portus进行用户认证\n\n# 什么是Registry和Index\n\n- 保存镜像层以及meta信息\n- 用户认证，UI等Web接口\n\n# Registry\n\n- 存储镜像\n- 控制自己的部署pipeline\n- \nintegrate image storage and distribution tightly into your in-house development workflow\n\n# Docker Distribution\n\n- 打包、传输、存储、交付内容的工具集\n- 以Registyry 2.0为主要产品\n- 还包括docs.docker.com的所有文档\n\n# Use cases\n\n- CI/CD\n- 大规模部署\n- 异地部署\n\n# 安装\n\n- Docker style\n- docker run -d -p 5000:5000 registry:2\n- 简单的难以置信\n- 软件交付方式\n- no wget && tar && pip install\n\n# 使用私有Registry\n\n- docker tag\n- docker push/pull\n\n# 使用私有Registry\n\n```bash\n# docker tag centos:7 myregistry.com:5000/centos:7\n# docker push myregistry.com:5000/centos:7\n```\n\n# 查看Registry内部\n\n```bash\n$ sudo docker exec -it registry bash\ncd /tmp\n```\n\n# 演示\n\n- 启动Registry\n- 向Registry push镜像\n\n\n# Storage Driver\n\n- 存储本身交给Storage Driver\n- 默认为本地文件系统，适合开发或者小规模\n- 也可以使用云存储，如S3、Azure和Ceph等，以及阿里云OSS\n- 甚至通过实现Storage API自定义storage backend\n\n\n# 将数据保存到Volume\n\n- -e REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/var/lib/registry\n- -v /myregistrydata:/var/lib/registry\n\n\n# 数据存储到Volume\n\n```bash\n$ docker run -d -p 5000:5000 \\\n  -e REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/var/lib/registry \\\n  -v /myregistrydata:/var/lib/registry \\\n  --restart=always --name registry registry:2\n```\n\n# Notification机制\n\n- webhooks/notification\n- log和report\n- email/bugsnap/newrelic\n\n# 安全对策\n\n- 支持TLS\n- 通过Nginx等进行basic authentication\n- 官方文档也有其他方式的认证和授权实现说明\n\n# 在公共网络上使用\n\n- 非localhost\n- 买一个证书（推荐）\n- 配置--insecure-registry\n- 自签名证书\n- 防火墙\n\n# 认证（Authentication）\n\n- docker login\n\n![](images/index-and-registry.png)\n\n# 认证\n\n- Basic（Proxy）认证\n- Token 认证（delegated authentication）\n\n# Basic（Proxy）认证\n\n- 简单\n- 准备证书\n- 创建用户密码\n\n# Token认证\n\n- 需要实现\n- 复杂、大型组织\n\n# Portus\n\n- 开源：MariaDB + Rails + Registry\n\n# 课后作业\n\n- 运行自己的私有Registry\n- 构建一个镜像并push到该Registry\n- 在本地删除该镜像\n- 从私有镜像pull出来\n"
  },
  {
    "path": "lesson-06/keynote.md",
    "content": "# Docker入门与实践\n\nLesson-06 Docker Hub和自动构建\n刘斌@Alauda\n2015年8月\n\n# 本节概要\n\n- Docker Hub功能简介\n- 在Docker Hub托管镜像\n- 自动构建\n\n# Docker Hub\n\n- 分发组件\n- 镜像托管\n- 系统办公\n- 免费和付费\n- 工作流\n\n# 主要功能\n\n- 镜像仓库\n- 自动构建（Automated Builds）\n- Webhooks\n- 组织（Organizations）\n- GitHub/Bitbucket集成\n\n# 官方镜像仓库\n\n- Official Repositories\n- docker-library/official-images\n- docker-library/docs\n\n# 官方镜像仓库标准\n\n- 基础OS镜像\n- 唾手可得的语言环境、软件\n- Dockerfile规范良好、文档详尽\n- 及时更新\n- 软件交付渠道\n\n# 和Docker Hub相关的命令\n\n- login/logout\n- pull/push\n- search\n\n# 自动构建\n\n- GitHub/BitBucket\n\n\n# 认证功能\n\n- ~/.docker/config.json\n\n# 自动构建过程\n\n- 添加commit hook\n- push后克隆到本地\n- 在本地build\n- 构建成功push镜像\n\n# 自动构建优势\n\n- 可信、可靠，保持最新\n- 支持GitHub/Bitbucket公开或私有仓库\n- 不能手工push镜像\n- 一个仓库对应多个自动构建\n- README.md即镜像说明\n\n\n# Repository links\n\n- 连接两个自动构建\n- 一个仓库有变化，则自动触发另一个仓库的自动构建\n- 不要循环连接\n\n\n# 远程构建触发器\n\n- Remote Build triggers\n- 通过POST发送构建请求\n- 5分钟只能请求1次\n- 上次构建未完成请求则被忽略\n- 指定镜像tag或Git的tag、分支等进行\n\n# Webhooks\n\n- HTTP call-back\n- 镜像更新时通知用户\n- Webhook chains\n\n# Webhook chains\n\n- 逐条执行\n- 前一hook验证（validate）之后，后一条才会执行\n- hook链只有全部hook都完成验证，才认为是完成。\n- 通过hook消息体中的callback_url进行POST验证\n- 验证消息内容\n- state：必选参数success/failure/error\n- description：显示在Docker Hub的详细信息，255字符\n- context：操作场景信息，100字符以内\n- target_url：用来查看hook执行结果的网址\n\n# 组织（团队）\n\n- Organizations and teams\n- Owners team具有创建team、仓库和自动构建的权限\n- 协作者 Collaborators\n- 读取私有仓库\n- 向非自动构建仓库push\n- Admin权限，修改仓库的描述，写作者；公开、私有以及删除仓库\n\n# 课后作业\n\n- 注册GitHub/Bitbucket和Docker Hub\n- 创建自动构建\n- 提交Dockerfile进行自动构建\n- 本地docker pull下载该自动构建镜像\n"
  },
  {
    "path": "lesson-07/keynote.md",
    "content": "# Docker入门与实践\n\nLesson-07 Docker Link\n刘斌@Alauda\n2015年8月\n\n# 本节概要\n\n- 什么是Docker Linxk\n- Docker Link的功能\n- Docker Link的用法\n\n# 为什么需要Docker Link\n\n- 如何连接到Docker容器？\n- docker inspect\n- docker port\n\n# 命名的重要性\n\n- happy_newton\n- 容易理解\n\n- --name选项\n- 唯一\n\n# Docker Link的好处\n\n- 方便引用\n- 类似白名单\n- 安全：只有引用者才能访问端口\n\n# 第一个Docker Link\n\n```bash\ndocker run -d --name db training/postgres\ndocker run -d -P --name web --link db:db training/webapp python app.py\ndocker inspect -f \"{{ .HostConfig.Links }}\" web\n\n```\n\n# 目的容器如何认识源容器？\n\n- 环境变量\n- /etc/hosts文件\n\n# 环境变量来自哪里？\n\n- Dockerfile\n- docker run -e|-env-file 选项\n\n# Docker Link添加的环境变量\n\n- 根据--link参数别名创建\n- 来自源容器（此处有安全隐患）\n\n# Docker Link添加的环境变量\n\n- <alias>_NAME\n- /<source_container>/<alias>\n\n# 和端口相关的环境变量\n\n- <alias>_PORT： WEBDB_PORT=tcp://172.17.0.82:8080\n- prefix： <name>_PORT_<port>_<protocol>\n- prefix_ADDR： WEBDB_PORT_8080_TCP_ADDR = 172.17.0.82\n- prefix_PORT： WEBDB_PORT_8080_TCP_PORT = 8080\n- prefix_PROTO： WEBDB_PORT_8080_TCP_PROTO = tcp\n- 环境变量数量 = n（port num） * 3\n\n# 源容器的其他环境变量\n\n- 全部\n- <alias>_ENV_<name>\n\n# 更新/etc/hosts\n\n- 在目标容器的/etc/hosts中，增加源容器条目\n\n# 更新/etc/hosts\n\n```bash\n$ docker run -t -i --rm --link db:webdb training/webapp /bin/bash\nroot@aed84ee21bde:/opt/webapp# cat /etc/hosts\n172.17.0.7  aed84ee21bde\n. . .\n172.17.0.5  webdb 6e5cdeb2d300 db\n\n```\n\n# /etc/hosts自动更新\n\n- 源容器重启后，会自动更新/etc/hosts条目\n- 环境变量不会更新\n- 建议使用/etc/hosts\n\n# 大使（ambassador）模式\n\n- 从 (consumer) --> (redis)\n- 到 (consumer) --> (redis-ambassador) --> (redis)\n- 或 (consumer) --> (redis-ambassador) ---network---> (redis-ambassador) --> (redis)\n- 解决跨主机通信\n\n\n# svendowideit/ambassador容器\n\n- socat\n- Docker Hub不活跃\n\n# 基于etcd的大使模式\n\n![](images/etcd-ambassador-flow.png)\n\n图片来源：https://coreos.com/assets/images/media/etcd-ambassador-flow.png\n\n\n# 课后作业\n\n- 在两个容器中使用link\n- 在目的容器中检查ENV，/etc/hosts等\n- 确认网络连通性\n\n"
  },
  {
    "path": "lesson-08/keynote.md",
    "content": "# Docker入门与实践\n\nLesson-08 Docker Volume\n刘斌@Alauda\n2015年8月\n\n# 本节概要\n\n- Docker Volume简介\n- 使用数据卷进行数据管理\n- 数据卷的备份和恢复\n\n# 容器的数据去哪里了？\n\n- 随着容器消失了。。。\n- 容器启动不了了，如何备份出来？\n- 如何共享数据？\n- 等等问题\n\n# 容器种类\n\n- 有状态（stateful）\n- 无状态（stateless）\n\n# 数据卷\n\n- 透过Union FS\n- 持久化（persistent）\n- 共享（share）\n\n# 数据卷的用途、特点\n\n- 拷贝base镜像中的数据到卷\n- 在容器中共享和重用\n- 绕过Union FS（CoW）\n- 不会影响容器和镜像\n- 和容器的生命周期无关\n\n# 创建数据卷的方式\n\n- docker run -v\n- Dockerfile VOLUME 指令\n- 默认在 /var/lib/docker 下\n\n# 加载host文件夹为卷\n\n- -v /src/webapp:/opt/webapp\n- Windows 和 OS X 要 加上 Users前缀\n- 不可在Dockerfile中使用\n\n# 实验\n\n- /host:/container\n- /host存在文件\n- /container存在文件\n- 两者都存在文件\n\n\n# 指定映射权限\n\n```bash\n/src/webapp:/opt/webapp:ro\n```\n\n# 也能mount单独文件\n\n```bash\ndocker run -v ~/.bash_history:/.bash_history\n```\n\n# 数据卷容器\n\n- data volume container\n- 在容器间共享数据\n\n# 创建数据卷容器\n\n```bash\n$ docker create -v /dbdata --name dbdata training/postgres /bin/true\n$ docker run -d --volumes-from dbdata --name db1 training/postgres\n$ docker run -d --volumes-from dbdata --name db2 training/postgres\n$ docker run -d --name db3 --volumes-from db1 training/postgres\n```\n\n\n# Dangling数据卷\n\n- 幽灵卷\n- docker rm -v\n\n# 数据备份、恢复和迁移\n\n```bash\n$ docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata\n```\n\n# 课后作业\n\n- 通过-v启动第一个容器\n- 在该容器中对volume中的数据进行修改\n- 启动第二个容器，使用--volumes-from\n- 在第二个容器中查看volume中的数据\n\n"
  },
  {
    "path": "lesson-09/example-1/Dockerfile",
    "content": "# Docker101 course, Lesson-9\nFROM python:2.7\nADD . /code\nWORKDIR /code\nRUN pip install -r requirements.txt\nCMD python app.py"
  },
  {
    "path": "lesson-09/example-1/app.py",
    "content": "from flask import Flask\nfrom redis import Redis\nimport os\napp = Flask(__name__)\nredis = Redis(host='redis', port=6379)\n\n@app.route('/')\ndef hello():\n    redis.incr('hits')\n    return 'Hello World! I have been seen %s times.\\n' % redis.get('hits')\n\nif __name__ == \"__main__\":\n    app.run(host=\"0.0.0.0\", debug=True)"
  },
  {
    "path": "lesson-09/example-1/docker-compose.yml",
    "content": "web:\n  build: . \n  command: python app.py \n  ports: \n   - \"5000:5000\" \n  volumes: \n   - .:/code \n  links: \n   - redis \n\nredis:\n  image: redis"
  },
  {
    "path": "lesson-09/example-1/requirements.txt",
    "content": "flask\nredis"
  },
  {
    "path": "lesson-09/example-2/docker-compose.yml",
    "content": "web:\n  image: wordpress\n  links:\n    - db:mysql\n  ports:\n    - 8080:80\n\ndb:\n  image: mariadb\n  environment:\n    MYSQL_ROOT_PASSWORD: rootASDF\n\n"
  },
  {
    "path": "lesson-09/keynote.md",
    "content": "# Docker入门与实践\n\nLesson-09 Docker Compose\n刘斌@Alauda\n2015年8月\n\n# 本节概要\n\n- 什么是Docker Compose\n- 使用Docker Compose构建多容器应用\n- Docker Compose用法详解\n\n# 什么是Docker Compose\n\n- 定义和管理多Docker容器应用的工具\n- 非常适合在开发、预演和CI环境下使用\n- 目前不建议在生产环境\n\n# Compose涵盖功能\n\n- 定义、运行多容器应用\n- 一个文件定义\n- 一条命令启动\n- 一条命了几乎能干任何事情,从启动到销毁\n\n# 三步使用Compose\n\n- 通过Dockerfile定义应用镜像\n- 通过docker-compose.yml定义服务，容器在一个统一的隔离环境\n- docker-compose up\n\n# Compose管理整个应用的生命周期\n\n- 构建镜像，启动停止服务\n- 管理服务\n- 管理日志\n- 执行单条命令\n\n# 启动第一个例子\n\n```bash\n$ docker-compose up -d\n$ docker-compose run web env\n$ docker-compose stop\n```\n\n# Compose命令说明\n\n- build：构建或者重新构建服务\n- kill：（SIGKILL）\n- kill -s SIGINT\n- logs：\n- port\n- ps\n- pull\n- restart\n- rm\n\n\n# Compose命令说明：run\n\n- docker-compose run web python manage.py shell\n- 自动创建volume\n- link容器也会被创建（--no-deps禁止自动创建）\n- 不会创建新的端口（--service-ports）\n\n# Compose命令说明： scale\n\n- docker-compose scale web=2 worker=3\n- 然并卵\n\n# Compose命令说明\n\n- start\n- stop\n- rm\n\n# Compose命令说明： up\n\n- 构建/创建/启动/attach到服务的容器中\n- 被Linked的服务会自动启动\n- -d\n- --no-recreate\n\n\n# 容器links\n\n- Compose使用容器links连接服务\n- docker-compose run SERVICE env\n\n# Compose参数说明：-f\n\n- -f -file\n- 默认 docker-compose.yml\n- 向上级文件夹递归查找\n\n# Compose参数说明：-p\n\n- -p, –project-name NAME\n- 默认为当前文件夹名。\n\n\n# Compose的环境变量\n\n- COMPOSE_PROJECT_NAME：默认为当前文件夹\n- COMPOSE_FILE：配置文件，默认为docker-compose.yml\n- DOCKER_HOST：默认为 unix:///var/run/docker.sock\n- DOCKER_TLS_VERIFY：非空为启用TLS\n- DOCKER_CERT_PATH：设置证书文件位置，默认为~/.docker\n\n\n# Compose配置文件说明\n\n\n- image\n- build\n- dockerfile\n- command\n\n# links\n\n- db\n- db:database\n- redis\n\n# external_links\n\n\n# extra_hosts\n\n- 等于--add-host参数\n- \"somehost:162.242.195.82\"\n- \"otherhost:50.31.209.229\"\n\n# ports\n\n- \"3000\"\n- \"49100:22\"\n- \"127.0.0.1:8001:8001\"\n- ！！使用字符串形式\n\n# expose\n\n- expose但是不向host发布\n- 只能在linked服务中使用\n\n# volumes\n\n- /var/lib/mysql\n- cache/:/tmp/cache\n- ~/configs:/etc/configs/:ro\n\n# volumes_from\n\n- service_name\n- container_name\n\n# environment\n\n- RACK_ENV: development\n- SESSION_SECRET:\n\n\n# env_file\n\n- 值或者list的形式\n- env_file: .env\n\n\n# extends\n\n- 继承模板文件\n- 可以覆盖模板中的设置\n- extends:\n-    file: common.yml\n-    service: web\n\n# extends\n\n- links和volumes_from需要在本地定义\n- 单值属性（image/command）： 覆盖\n\n# extends 多值属性\n\n- 串接： ports/expose/external_links/dns/dns_search\n- 按key merge： environment/labels\n- 按value merge： volumes/devices\n\n# labels\n\n- 容器的metadata\n- 建议使用DNS标记法以防冲突\n- com.example.description: \"Accounting webapp\"\n- \"com.example.description=Accounting webapp\"\n\n# log driver\n\n- 等于docker run --log-driver\n- 可以指定为json-file,syslog和none\n- 默认为json-file\n\n# net\n\n- 等于 docker run --net参数\n- net: \"bridge\"\n- net: \"none\"\n- net: \"container:[name or id]\"\n- net: \"host\"\n\n# 其他参数\n\n- dns, dns_search\n- pid\n- cap_add, cap_drop\n\n\n# 其他参数\n\n```bash\ncap_add:\n  - ALL\ncap_drop:\n  - NET_ADMIN\n  - SYS_ADMIN\nsecurity_opt:\n  - label:user:USER\n  - label:role:ROLE\n```\n\n# 和docker run一样的参数\n\n- working_dir\n- entrypoint\n- user\n- hostname\n- mem_limit\n- privileged\n- restart\n- cpu_shares\n- cpuset\n\n\n# Docker Compose的局限\n\n- 面向单主机\n- 不能解决网络和存储问题\n\n# 课后作业\n\n- 运行同目录下的例子\n- 构建自己的应用栈：App + DB\n"
  },
  {
    "path": "lesson-10/keynote.md",
    "content": "# Docker入门与实践\n\nLesson-10 Docker Machine\n刘斌@Alauda\n2015年8月\n\n# 本节概要\n\n- 什么是Docker Machine\n- 使用Machine创建Docker主机\n- 使用Machine在Digital Ocean上创建主机\n- Machine命令讲解\n\n# 什么是Docker Machine\n\n![](../lesson-01/images/docker-machine-logo.png)\n\n# 背景\n\n- 大量服务的provisioning\n- 手工安装、升级的麻烦\n\n# Docker Machine\n\n- 创建Docker主机运行环境\n- 创建服务器\n- 配置Docker\n- 配置客户端环境变量\n\n# Docker Machine\n\n- 远程控制主机：\n- 启动、停止和重启\n- 升级Docker\n- 配置客户端环境变量以和Daemon通信\n\n# 实验操作环境\n\n- HOST： OS X\n- Driver： VirtualBox、Digital Ocean\n\n# 创建VirtualBox主机\n\n```bash\ndocker-machine create --driver virtualbox dev\neval \"$(docker-machine env dev)\"\ndocker run busybox echo hello world\n```\n\n# 在云主机上使用Docker Machine\n\n- 创建digitalocean token\n\n# 在云主机上使用Docker Machine\n\n```bash\ndocker-machine create \\\n    --driver digitalocean \\\n    --digitalocean-access-token xxxxxxxxxxx \\\n    --digitalocean-image centos-7-0-x64 \\\n    --digitalocean-region \"sfo1\" \\\n    --digitalocean-size \"512mb\" \\\n    do\n```\n\n# Digital Ocean 参数\n\n- --digitalocean-access-token\n- --digitalocean-image\n- --digitalocean-region\n- --digitalocean-size\n- --digitalocean-ipv6\n- --digitalocean-private-networking\n- --digitalocean-backups\n\n# 子命令说明：create\n\n- create\n- docker-machine create -d virtualbox\n\n# 子命令说明：create\n\n- --engine-insecure-registry registry.myco.com\n- --engine-registry-mirror\n- --engine-label\n- --engine-storage-driver\n\n# 子命令说明：create\n\n- --engine-opt dns=8.8.8.8\n- --engine-opt log-driver=syslog\n\n# 子命令说明：create\n\n- --swarm\n\n# 子命令说明：env\n\n- docker-machine env machinename\n- eval \"$(docker-machine env machinename)\"\n\n# 子命令说明：ls\n\n- docker-machine ls --filter driver=virtualbox --filter state=Running\n- driver（driver name）\n- swarm（swarm master’s name）\n- state（Running|Paused|Saved|Stopped|Stopping|Starting|Error）\n\n# 子命令说明：ssh\n\n- docker-machine ssh dev\n- docker-machine ssh dev COMMAND\n- docker-machine ssh dev -- df -h\n\n# 子命令说明：其他\n\n- start\n- stop\n- restart（=stop && start）\n- rm\n\n# 子命令说明：其他\n\n- inspect （-f）\n- ip\n- upgrade\n- scp\n\n\n# 子命令说明：其他\n\n- active\n- config\n- kill（强制停止）\n\n\n\n# 课后作业\n\n- 使用VirtualBox创建Docker主机\n- 有条件的话可以在云服务器上创建Docker主机\n\n"
  },
  {
    "path": "lesson-11/keynote.md",
    "content": "# Docker入门与实践\n\nLesson-11 Docker Swarm\n刘斌@Alauda\n2015年8月\n\n# 本节概要\n\n- Swarm简介\n- 动手试用Swarm\n- Swarm深入讲解\n\n# 什么是Swarm\n\nDocker Swarm is native clustering for Docker. It allows you create and access to a pool of Docker hosts using the full suite of Docker tools. \n\n![](../lesson-01/images/docker-swarm-logo.png)\n\n# Docker集群软件出现的背景\n\n- 应用架构变复杂\n- 高可用、大规模应用的普及\n- 资源池化\n\n# 什么是Swarm\n\n- 原生Docker集群\n- 跨主机创建容器\n- 兼容Docker Remote API\n- BETA中\n\n# 什么是Swarm\n\n- 资源抽象层\n- 原则：可交换，可插拔，通过API\n- 第三方或自己定制的调度组件\n\n# 架构\n\n- Manager 节点\n- Agent 节点\n\n# 实验环境\n\n- OS X\n- Docker Machine\n\n\n# 实验步骤\n\n- 拉取Swarm镜像\n- 通过swarm create获得集群id\n- 创建swarm集群（及master节点）\n- 创建集群Agent节点\n\n# Swarm组件解析\n\n- Discovery\n- Scheduler\n\n# 发现（Discovery）组件\n\n- 让节点能找到所要加入的集群\n\n# 发现组件的实现方式\n\n- 基于Docker Hub的发现服务\n- 静态文件（file参数）\n- etcd\n- consul\n- zookeeper\n- 静态服务器列表（nodes参数）\n- 定制Backends\n\n# 自定义服务发现\n\n- DiscoveryService接口\n- Initialize\n- Fetch\n- Watch\n- Register\n\n# Scheduler组件\n\n- Strategies\n- Filters\n\n# Strategies\n\n- Ranking（打分）\n- swarm manage --strategy\n\n# 目前支持的策略\n\n- spread（默认）\n- binpack\n- random\n\n# spread & binpack\n\n- 按照可用CPU、内存以及运行中容器数为节点打分\n- spread：最少容器运行 -> 容器平均分布\n- binpack：最拥挤 -> 避免碎片化，最大限度利用资源\n\n# Filters\n\n- Constraint\n- Affinity\n- Port\n- Dependency\n- Health\n\n# Constraint Filter\n\n- 指定某一节点\n- key-value tags\n- storage=ssd\n- storage=disk\n\n# Constraint Filter\n\n- docker -d --label storage=ssd\n- docker run -e constraint:storage==ssd\n\n# 标准约束Standard Constraints\n\n- node ID or node Name (using key “node”)\n- storagedriver\n- executiondriver\n- kernelversion\n- operatingsystem\n\n# 亲和度（Affinity）filter\n\n- 通过指定关系的亲密程度来选择节点\n- 指定容器或镜像\n- 或者label\n- 确保容器运行于同一网络节点上\n\n# Container affinity\n\n- 与指定的容器ID或name运行在同一节点\n\n# Container affinity\n\n```bash\ndocker run --name frontend\ndocker run -e affinity:container==frontend\n```\n\n# Image affinity\n\n- -e affinity:image==redis\n- -e affinity:image==06a1f75304ba\n\n# Container Label affinity\n\n```bash\ndocker run --label com.example.type=frontend\ndocker ps  --filter \"label=com.example.type=front\"\ndocker run -e affinity:com.example.type==frontend \n```\n\n# Filter表达式语法\n\n- constraint:node==node1\n- constraint:node!=node1\n- constraint:region!=us*\n- constraint:node==/node[12]/\n- constraint:node==/node\\d/\n- constraint:node!=/node-[01]/\n\n# Soft Affinities/Constraints\n\n- Affinities/Constraints 不满足，容器不会被启动\n- Soft Affinities/Constraints （~）：不满足则丢弃约束\n- -e affinity:image==~redis\n- -e constraint:region==~us*\n- -e affinity:container!=~redis*\n\n# Port Filter\n\n- 因为Port是稀缺且排他的资源\n\n# Dependency Filter\n\n- 两个容器必须要在同一node工作\n- 如果不能找到满足条件的node，则拒绝创建新容器\n\n# Dependency Filter 类型\n\n- Volumes: --volumes-from=dependency\n- Links: --link=dependency:alias\n- Network stack: --net=container:dependency\n\n# Health Filter\n\n- 避免容器被分配到不健康的节点\n\n# 课后作业\n\n- 使用Docker Machine创建Swarm集群\n- 1个master，2个node\n\n\n"
  },
  {
    "path": "lesson-12/keynote.md",
    "content": "# Docker入门与实践\n\nLesson-12 Docker网络\n刘斌@Alauda\n2015年8月\n\n# 本节概要\n\n- Linux网络基础\n- iptables基础知识\n- Docker的网络实现原理\n- Docker和网络相关的参数和配置bash\n- 对Docker进行简单的网络定制\n- 一些网络解决方案（SDN）\n\n# Linux 网络设备\n\n- eth0\n- lo\n- ip命令\n\n# Linux网络文件说明\n\n- /etc/hostname\n- /etc/hosts\n- /etc/resolv.conf\n\n# 演示1\n\n- 在容器内\n- ip addr show\n- 查看/etc/hostname\n- /etc/hosts\n- /etc/resolv.conf\n\n\n# iptables基础知识\n\n- 防火墙\n- NAT\n\n# iptables的4个表\n\n- filter\n- nat\n- mangle\n- raw\n\n# iptables的4个表\n\n```bash\n$ sudo iptables -t filter -L\n```\n\n# Docker中的网络\n\n- Network NS\n- iptables\n- 网桥\n\n# docker0网桥\n\n- 172.17.42.1/16\n- 16bit的网络，有65534个地址可用\n- 连接host和所有容器的虚拟子网\n\n# Docker容器运行的4种网络模式\n\n- bridge\n- host\n- 容器\n- overlay（实验版）\n- none\n\n# bridge模式\n\n- --net=bridge\n- 默认模式。172段IP地址。\n\n![](./images/docker_bridged.png)\n\n图片来源：http://blog.midonet.org/docker-networking-midonet/\n\n# host\n\n- --net=host\n- 共享主机IP地址、网卡设备、主机名等。\n\n# 容器模式\n\n- --net=container:(id/name)\n- 共享其他容器网络环境\n\n![](./images/docker_container.png)\n\n图片来源：http://blog.midonet.org/docker-networking-midonet/\n\n# none无网络模式\n\n- --net=none\n- 容器启动时，无任何网络。\n- 可手工配，适用于需要对网络结构进行特殊定制的情形。\n\n# docker run 参数\n\n- docker run -h hostname\n- --dns-search=192.168.10.100\n- docker run -d -p 8080:8080\n\n\n# -p和-P参数\n\n- -P 随机分配宿主机端口，49000~49900\n- -p 详细配置端口映射\n- - 8080:80\n- 127.0.0.1:8080:80\n- 127.0.0.1::80\n\n# docker port查看端口映射\n\n- docker port 80\n\n# 和网络相关的命令行参数\n\n- 只能在daemon中使用\n- 只能在client中使用\n- 在daemon和client中都能使用\n\n# 只能在daemon中使用的参数\n\n- -b BRIDGE or --bridge=BRIDGE\n- --bip=CIDR\n- --default-gateway=IP_ADDRESS\n- --fixed-cidr\n- --default-gateway-v6=IP_ADDRESS\n\n- -H SOCKET... or --host=SOCKET... daemon监听接口\n- --icc=true|false\n- --ip=IP_ADDRESS\n- --ip-forward=true|false\n\n- --iptables=true|false\n- --mtu=BYTES\n--userland-proxy=true|false\n\n# 只能在docker run中使用\n\n- -h HOSTNAME or --hostname=HOSTNAME\n- --link=CONTAINER_NAME_or_ID:ALIAS\n- --net=bridge|none|container:NAME_or_ID|host\n- --mac-address=MACADDRESS...\n- -p SPEC or --publish=SPEC\n- -P or --publish-all=true|false\n\n\n# 在client和daemon都能使用\n\n- --dns=IP_ADDRESS\n- --dns-search=DOMAIN\n\n\n# /etc下的三个关键文件\n\n```bash\nmount | grep /etc\n\n/dev/vda1 on /etc/resolv.conf type ext4 (rw,relatime,data=ordered)\n/dev/vda1 on /etc/hostname type ext4 (rw,relatime,data=ordered)\n/dev/vda1 on /etc/hosts type ext4 (rw,relatime,data=ordered)\n```\n\n# hostname和hosts\n\n- -h HOSTNAME or --hostname=HOSTNAME\n- /etc/hostname\n- /etc/hosts\n- shell提示符\n\n# hostname和hosts\n\n- --link=CONTAINER_NAME_or_ID:ALIAS\n- /etc/hosts 中添加  ALIAS\n- ALIAS重启后，自动更新/etc/hosts\n\n# resolv.conf\n\n- --dns=IP_ADDRESS... \n- /etc/resolv.conf添加server行\n- --dns-search=DOMAIN... \n- 在/etc/resolv.conf添加search行\n\n# 容器通信\n\n- 容器之间\n- 容器访问外部\n- 外部访问容器\n\n# 容器和外部通信\n\n- host是否允许包转发\n- iptables是否允许容器间连接\n\n# host上的包转发\n\n- ip_forward ，设置1时容器间可以通信\n- --ip-forward=true一样效果\n\n# host上的包转发\n\n```bash\n# sysctl net.ipv4.conf.all.forwarding=1\n# sysctl net.ipv4.conf.all.forwarding\nnet.ipv4.conf.all.forwarding = 1\n```\n\n# Docker iptables设置\n\n- --iptables=false，Docker不会进行iptables设置\n- 默认会在DOCKER过滤链中添加规则\n\n# 容器间通信\n\n- 网络拓扑结构上是否能互通\n- iptables是否允许（--icc=true）\n- 在FORWARD链添加ACCEPT策略\n- --icc=false. 则为DROP\n\n# icc=false时容器如何互连？\n\n- --icc=true，安全性问题\n- 使用link可以解决\n- --icc=false 并且 --iptables=true \n\n# 外部如何连接到容器？\n\n- iptables masquerade 规则\n- 运行容器访问外部世界\n\n# 外部如何连接到容器？\n\n```bash\niptables -t nat -L -n\nChain POSTROUTING (policy ACCEPT)\ntarget     prot opt source               destination\nMASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0\n```\n\n# 外部如何连接到容器？\n\n- 使用-P或者--publish-all=true，EXPOSE所有Dockerfile里的端口\n- --expose <端口号>\n- 映射到host端口上\n- host端口范围由/proc/sys/net/ipv4/ip_local_port_range 控制\n- 一般为 32768 to 61000\n\n# -p和-P的区别\n\n- -p 小p是精确映射\n- -P expose出全部镜像定义的端口\n\n\n# -P（大P）时iptables规则\n\n```bash\niptables -t nat -L -n\nChain DOCKER (2 references)\ntarget     prot opt source               destination\nDNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:49153 to:172.17.0.2:80\n```\n\n# -p（小p）时iptables规则\n\n```bash\nChain DOCKER (2 references)\ntarget     prot opt source               destination\nDNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.17.0.2:80\n```\n\n# 定制docker0\n\n- --bip=CIDR —docker0网桥IP地址，CIDR格式，如192.168.1.5/24\n- --fixed-cidr=CIDR—IP范围  docker0子网,  like 172.167.1.0/28\n- --mtu=BYTES  docker0的最大传输单元大小\n\n\n# 容器启动时所做的网络工作\n\n- 在host中创建虚拟设备对vethXXXX\n- 将vethXXXX绑定到docker0网桥\n- 将设备对的另一端放入容器，命名为eth0\n- 独立网络namespace，不用担心各种冲突\n- 为eth0设置mac（用户可指定）和IP地址（不能指定）\n- 默认路由为docker0网桥的IP地址\n\n# 模拟Docker网络设置过程\n\n- 实验演示\n- 模拟Docker为容器创建网络设备\n\n# 创建点对点连接\n\n- 虚拟设备对从host-container到container-container\n- 配置为点对点连接\n- 可和其他网络模式并用\n\n# 然而需求源源不断\n\n- IP重用\n- 任意指定IP\n- 跨主机通信\n- 从外部直接访问容器网路\n- L2/L3跨主机虚拟网络\n\n\n# pipework\n\n- Jérôme Petazzoni，Docker公司布道师\n- https://github.com/jpetazzo/pipework\n- ip/brctl/ovs-vsctl\n- VLAN/macvlan/Open vSwitch\n- DHCP\n\n# 修改容器内网络配置文件\n\n- /etc/hosts,/etc/hostname,/etc/resolve.conf\n- 只能在running的容器中\n- docker commit 不能保存\n- docker restart 也会丢失\n\n# libnetwork\n\n- SocketPlane\n- 2015.3被Docker inc.收购\n- Multi-Host Container Networking\n\n![](./images/socketplane.png)\n\n# libnetwork\n\n- 跨平台的容器网络库\n- libcontainer的网络版\n- 轻量、高模块化、可组装、独立工作的工具\n- “batteries included but swappable”\n\n![](./images/docker-turtles-communication.jpg)\n\n# CNM组件\n\n- Container Network Model (CNM)实现\n- Sandbox（网络栈配置，Linux Network NS ）\n- Endpoint（将Sandbox连接到Network，veth）\n- Network（一组可以互相通信的Endpoint，Linux网桥/VLAN）\n\n# CNM组件\n\n![](./images/cnm-model.jpg)\n\n# CNM对象（Objects）\n\n- NetworkController\n- Driver\n- Network\n- Endpoint（Service Endpoint）\n- Sandbox\n\n# Drivers\n\n- null\n- bridge\n- overlay（实验版experimental）\n- remote\n\n# 第三方网络解决方案\n\n- weave\n- flannel\n- Calico\n- Triton\n\n# weave\n\n- Weaveworks开发\n- 高效的连接、监视和控制Docker容器的方式\n\n# weave\n\n- virtual network\n- 跨主机、自动发现\n- 不需要配置link，端口映射等\n- 轻松对外发布weave network上的服务\n\n![](images/weave-arch.png)\n\n# flannel\n\n- CoreOS开发\n- 基于etcd的容器网络编配\n- Agent： flanneld\n\n# flannel\n\n![](images/flannel-packet.png)\n\n# flannel Backends\n\n- udp\n- vxlan\n- host-gw\n- aws-vpc\n- gce\n- alloc\n\n\n# 课后作业\n\n- 练习iptables命令\n- 使用--net=host启动容器，查看网络配置\n- 使用--net=container启动容器，查看网络配置\n- 使用--net=none，手工为容器配置网络\n"
  },
  {
    "path": "lesson-13/docker-compose.yml",
    "content": "wordpress:\n  image: index.alauda.cn/library/wordpress:3\n  links:\n    - db:mysql\n  ports:\n    - \"80/http\"\n  environment:\n    - WORDPRESS_DB_PASSWORD: password\n  volumes:\n    - /var/www/html:10\n  size: M\n\ndb:\n  image: index.alauda.cn/library/mysql:5\n  ports:\n    - \"3306/tcp\"\n  environment:\n    - MYSQL_ROOT_PASSWORD: password\n  volumes:\n    - /var/lib/mysql:10\n  size: M\n"
  },
  {
    "path": "lesson-13/keynote.md",
    "content": "# Docker入门与实践\n\nLesson-13 Docker CaaS\n刘斌@Alauda\n2015年8月\n\n# 本节概要\n\n- 什么是CaaS\n- 灵雀云功能简介\n- 使用灵雀云创建有状态服务\n- 数据备份和恢复\n- alauda命令行工具介绍\n\n# 什么是CaaS\n\n- 容器即服务\n- 托管镜像，而不是代码\n\n# CaaS的优势\n\n- 服务于完整开发周期\n- 优化开发－运维整体流程\n- 提高产品开发迭代速度，缩短交付周期\n- 高可用、高性能、高密度、高动态的容器服务\n- 降低IT成本\n\n# 灵雀云基本功能\n\n- 镜像加速\n- 共有、私有镜像托管\n- 容器托管\n- 一键部署，自动修复、扩展\n- 镜像市场\n- 国内外数据中心\n\n# 灵雀云特色功能\n\n- 持久存储卷（Persistent Storage Volume）\n- 存储卷备份（Storage Volume Backup）\n- 内部通信（Internal Endpoint）\n\n# 灵雀云特色功能\n\n- 跨主机容器关联，四层、七层负载均衡\n- 灵雀云命令行（Alauda CLI），一键发布任何容器化应用\n- Alauda Compose\n- EXEC\n\n# alauda _EXEC\n\n- docker exec on Web\n\n# 使用灵雀云创建有状态服务\n\n- 什么是有状态服务\n- 创建Wordpress网站\n\n# 数据备份和恢复\n\n- 备份数据库文件\n- 以备份文件创建新服务\n\n# alauda命令行工具介绍\n\n- Python编写，开源\n- pip install\n\n# alauda命令\n\n- alauda ps\n- alauda stop\n- alauda rm\n- alauda service\n\n# alauda compose\n\n- 兼容Docker Compose语法\n- alauda compose up\n- alauda compose ps\n- alauda compose start\n- alauda compose rm\n\n# alauda compose\n\n- 创建Wordpress应用\n\n\n# 课后作业\n\n- 试用alauda.cn\n- 创建有状态容器\n- 使用volume\n- 进行volume的备份和恢复\n\n"
  },
  {
    "path": "lesson-14/Dockerfile",
    "content": "FROM centos:7 \n\nMAINTAINER bin liu <liubin0329@gmail.com>\n\nRUN yum update -y\n\n# 安装Java和Git\nRUN yum install -y java-1.8.0-openjdk git\n\nENV JENKINS_HOME /opt/jenkins/data\nENV JENKINS_MIRROR http://mirrors.jenkins-ci.org\n\n# 下载Jenkins的war包\nRUN mkdir -p $JENKINS_HOME/plugins\nRUN curl -sf -o /opt/jenkins/jenkins.war -L $JENKINS_MIRROR/war-stable/latest/jenkins.war\n\n# 安装Jenkins插件\nRUN for plugin in chucknorris greenballs scm-api git-client git ws-cleanup ;\\\n    do curl -sf -o $JENKINS_HOME/plugins/${plugin}.hpi \\\n       -L $JENKINS_MIRROR/plugins/${plugin}/latest/${plugin}.hpi ; done\n\nEXPOSE 8080\n\n# 添加启动命令\nCMD [\"java\", \"-jar\", \"/opt/jenkins/jenkins.war\"]\n"
  },
  {
    "path": "lesson-14/keynote.md",
    "content": "# Docker入门与实践\n\nLesson-14 基于Docker进行CI（持续集成）\n刘斌@Alauda\n2015年8月\n\n# 本节概要\n\n- 什么是CI和Jenkins\n- 普通CI的流程\n- 如何使用Docker + Jenkins进行CI\n\n# 测试需求\n\n- 频繁进行\n- 干净环境\n- 打包安装费时\n- 环境复杂\n- 自动化\n- 持续交付\n\n# 什么是CI（Continuous Integration）\n\n- 持续集成\n- 早集成，常集成\n\n# 在CI中使用Docker的优势\n\n- 轻量快速\n- 可复用（Dockerfile，镜像）\n- 隔离（干净环境）\n\n# Jenkins简介\n\n- 开源CI服务\n- SCM/部署\n- plugin\n- war文件发布，不需要数据库\n- Web界面配置\n- email通知\n- 生成JUnit/TestNG报告\n- 分布式构建支持\n\n![](./images/jenkins_logo.png)\n\n# Jenkins + Docker 模式\n\n- Git hook -> Jenkins -> Build Docker 镜像-> 测试\n- 不仅仅是效率的提升，更是一种变革\n- DevOps紧密结合\n\n# Jenkins + Docker\n\n- Jenkins和测试都跑在容器中\n- Docker in Docker\n\n# Jenkins + Docker\n\n```bash\na=$(sudo docker run -d --net=host -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v /sys:/sys -v /lib64:/lib64 -p 8080:8080 j4)\n```\n\n# 实验\n\n- 在Docker中使用Jenkins进行测试\n\n# 课后作业\n\n- 运行本示例代码\n\n"
  },
  {
    "path": "lesson-15/keynote.md",
    "content": "# Docker入门与实践\n\nLesson-15 延伸阅读\n刘斌@Alauda\n2015年8月\n\n# 本节概要\n\n- 总结本系列课程\n- Docker的扩展知识\n- Docker的生态环境\n\n# 四大问题\n\n- 存储\n- 网络\n- 编配（集群管理）\n- 工作流\n\n# 解决方式\n\n- Docker自身的进化\n- 生态系统\n- 软件架构、工作流的进化\n\n# Docker产品\n\n- 编排\n- DevOps\n\n# 生态系统\n\n- There is no platform without ecosystem.\n- by Solomon Hykes @DockerCon2015\n\n# 存储\n\n- Flocker\n\n![](./images/flocker.png)\n\n# PaaS\n\n- Dokku\n- Deis\n- Flynn\n\n# Deis\n\n![](./images/deis.png)\n\n# 编排\n\n- Mesos\n- Kubernetes\n\n# 管理界面\n\n- docker-ui\n- openstack horizon\n- shipyard\n- Portus\n\n# 配置管理\n\n- chef\n- puppet\n- salt\n- Ansible\n\n# CI\n\n- jenkins\n- drone\n- strider\n- travis\n\n\n# 容器OS\n\n- CoreOS\n- Project Atomic\n- Hyper\n- http://rancher.com/\n\n# rkt（Rocket）\n\n- App Container runtime for Linux\n- CoreOS主导开发\n- \"rock-it\"\n\n![](images/rkt.png)\n\n# rkt特点\n\n- 没有daemon和Registry\n- 深度集成init（systemd，upstart）\n- 编配工具（fleet，k8s）\n- 兼容Docker镜像\n- 模块化、可扩展\n\n# LXD\n\n- Canonical 主导\n- 基于LXC，有daemon，REST API\n- lxc为客户端\n- OpenStack Nova plugin (nova-compute-lxd)\n- live migration\n\n![](images/lxd.png)\n\n# 开放容器组织\n\n- OCI（ Open Container Initiative， https://www.opencontainers.org/ ）\n- RunC（ http://runc.io/ ）\n\n# RunC\n\n- Runtime\n- 基于libcontainer\n- 没有Daemon\n- 没有镜像管理但兼容Docker镜像\n\n![](./images/hamster.png)\n\n\n"
  }
]