标签 Docker 下的文章

Linux 容器正在改变 IT 从业者的工作方式。相比于庞大、沉重的虚拟机,一些组织发现把他们的应用部署在容器中更有效,可以提供更快的速度,更加密集,提升他们操作的敏捷性。

从安全的角度看,容器带来了一些优势,但是也面临着它们自己的一些安全挑战。和传统的基础设施一样,为了避免安全缺陷,确保运行在一个容器内的组件和系统库的定期更新是至关重要的。但是你如何知道什么东西运行在你的容器内?为了帮助你应对这些的安全挑战,一个名为 Anchore的初创公司正在开发一个同名的开源项目,它用来帮助展示 Linux 容器中的内容。

为了了解更多关于 Anchore,我找到了 Anchore 的市场和产品的发言人 Andrew Cathrow,来了解更多关于这个开源项目背后的公司。

简而言之 Anchore 是什么? 它如何工作?

Anchore 的目标是提供一套工具,允许开发人员、运营团队、安全团队在容器的整个开发周期中保持对“监管链(Chain of Custody)”的全程可见,并提供生产部署所需的可见性、可预测性和控制性。Anchore 的引擎通过插件可以进行分析(通过提取镜像数据和元数据)、查询(允许对容器进行分析)、以及策略评估(这里的策略指可以被指定的管理的图像)。

虽然市场上有很多扫描工具,但是大部分不开源。我们认为安全合规的产品应该是开源的,否则你怎么才能信任他们。

Anchore 除了开源以外,还有两大优势,使它可以区别于市场中的商业产品。

首先,我们看的不止是操作系统的镜像。如今的扫描工具专注于操作系统的软件包,比如“你的 RPM 或 DEB 包中有CVE(安全漏洞)么?”这虽然是很重要的,你不希望你的镜像中有不安全的包,但是操作系统包只是镜像的基础。其他的层次都需要进行验证,包括配置文件、语言模块、中间件等等。你可以用的全是最新的软件包,但是可能一个配置文件配置出现错误,不安全就出现在里面。第二个不同就是允许用户添加自己的数据、查询或策略来扩展这个引擎。

什么推动了容器的校验和分析工具的需求出现?这个工具可以解决运营面临的什么问题呢?

企业使用 Docker 首要关注的就是安全,特别是他们正在部署的容器的分配和合规性。在生产环境中,从公共镜像库拉取一个镜像,运行它,并在几秒钟部署,是非常简单的,甚至不知道下面可能发生什么。终端用户在部署应用时,必须信任他们所部署的是安全、高效和易于维护的。

容器是不透明的,它们是一个包含应用程序的可部署的“黑盒”。虽然非常容易把这些镜像看作“打包的应用程序”,但是它们包括了系统的镜像和多达数百个包和成千上万个文件。如同所有在物理服务器、虚拟机或者云上的操作系统一样,镜像也需要维护。镜像或许包含了未补丁的安全缺陷、带有 bug 和错误配置的过期软件。

要对您的容器部署有信心,你需要知道底层是什么,并基于容器镜像的内容来做出决定。

如今容器的创新基本上都是开源的,你认为是为什么呢?是什么促使了它们开源呢?

在过去的 20 年中,各个组织已经经历了开源带来的优势,节省成本,减少锁定,提高了安全性和更快的创新。容器,特别是 Docker,都是非常好的例子。Docker 公司的团队不能在专有系统上创建一个新的软件部署模式,他们不能要求在修改专有系统的代码,而是与行业领导者比如谷歌、IBM、英特尔、红帽合作,朝着一个共同的目标。开源和 Linux 总是开启创新和激励产业困境。在过去,实现一个大的想法需要一个大的团队和很多资源。在开源世界,一个有着很大的创意的小公司可以工作在一个更大的社区中,通过知识共享的力量来协作,提供真正的企业创新。

为了深入的说明开源的使用,Anchroe 团队最近刚从多伦多的 LinuxCon 回来,在哪里,令人难以相信的是,微软作为钻石级的赞助商,展示了他们用在 Linux 上的产品投入的增长。Linus Toravlds 曾说过,“如果微软为 Linux 开发应用就意味着我赢了”。我要把这句话改为“开源赢了”。

容器领域的通用标准的创建还需要时间,在容器的几乎所有部分,仍有许多挑战。在这个领域,创业公司有哪些挑战?

这里有个很重要的点,就是没有开放的标准和开源,我们不可能看到快速推动容器的采用和改变行业格局的创新。开放容器倡议(OCI)由 Linux 和容器行业的行业领导者组成,正在为运行环境和镜像格式创造标准,这将使我们能够看到更多的创新。Anchore 很自豪能成为 OCI 的新成员,我们期待帮助形成标准。

你将如何围绕 Anchor 项目建立一个开源社区?

Anchore 团队来自 Ansible、Eucalyptus Systems 和 Red Hat 的领导团队,在开源社区中拥有丰富的工作经验。从一开始,Anchore 就准备创建一个强大的开源社区,我们正在应用我们在开源世界中学到的经验和教训。第一课,当然,发布要尽早尽快。我们在 6 月开源我们的检测和分析引擎,远远早于我们的商用产品,以便了确保开源项目能够独立运行,使更多的直接用户能够使用它,而无需购买 Anchore 的商用产品。通过支持、服务和增强型的数据源,有很多机会给商用产品创造更多价值,但是如果开源引擎本身没有用,我们将看不到活跃的社区。

我们将 Anchore 模块化,允许添加分析、报告和策略插件,而不需要更改核心的引擎。我们希望保证任何人都可以创建插件,所以我们选择了 Python 作为项目的基本语言,因为 Python 被开发者和系统管理员广泛应用。但是,即使你不熟悉 Python,你仍然可以使用任何你喜欢的语言或者脚本环境创建插件。如果你可以创建一个 Bash 脚本,那么你也可以创建一个 Anchore 插件。我们的目标是最大化的吸引社区的参与。虽然我们鼓励用户将贡献回馈给社区,但是我们也为这个项目构建并进行了授权,来确保可以独立创建和维护私有的插件和模块。

容器的用途不止是在服务器上更大密度的部署应用程序或者技术层面更快的速度,而且还有不同工具的组合,这些工具提供了一种不同的方式来拉近开发者和操作者共同工作。作为在这个领域工作的公司,你们希望提供一个什么样的消息来让开发者和运营产生共鸣?

随着越来越多的运行环境、编排、监控和集成产品,容器的生态系统正在快速发展。所以,我们的架构中的第一个考虑因素不是限定 Anchore 的部署和使用。我们需要确保我们可以适应任何 CI/CD 工作流,无论是私有部署还是云端部署。一个经常问到我们的问题是,Anchore 是否将提供一个包含了镜像扫描和分析的容器仓库。虽然这将大大简化我们的工作,但是这会迫使用户进入特定的部署架构,并限制了用户部署他们自己最好的组件的能力。我们已经确保 Anchore 可以和所有领先的仓库、运行环境平台、 CI/CD 平台和编排工具配合使用。

一些开发者掌握了运营技能,并转换为 DevOps 角色,我们看到系统管理员/运营团队也在更多的了解开发,转换成 DevOps 角色。我们也看到了具有混合能力的团队。我们设计了可供开发运营和安全团队使用的 Anchore ,以便他们共同定义规则和策略来评估开发周期中的任何一个环节。另外一个例子是插件/模块的架构,使任何人都可以在他们喜欢的环境中轻松创建一个模块 —— 无论是以 Python、Go、Perl、C 甚至是一个 Bash 脚本。


via: https://opensource.com/business/16/10/interview-andy-cathrow-anchore

作者:Jason Baker 译者:Bestony 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

嗨,在本教程中,我们将学习如何使用 docker 部署 golang web 应用程序。 你可能已经知道,由于 golang 的高性能和可靠性,docker 是完全是用 golang 写的。在我们详细介绍之前,请确保你已经安装了 docker 以及 golang 并对它们有基本了解。

关于 docker

Docker 是一个开源程序,它可以将应用及其完整的依赖包捆绑到一起,并打包为容器,与宿主机共享相同的 Linux 内核。另一方面,像 VMware 这样的基于 hypervisor 的虚拟化操作系统容器提供了高级别的隔离和安全性,这是由于客户机和主机之间的通信是通过 hypervisor 来实现的,它们不共享内核空间。但是硬件仿真也导致了性能的开销,所以容器虚拟化诞生了,以提供一个轻量级的虚拟环境,它将一组进程和资源与主机以及其它容器分组及隔离,因此,容器内部的进程无法看到容器外部的进程或资源。

用 Go 语言创建一个 “Hello World” web 应用

首先我们为 Go 应用创建一个目录,它会在浏览器中显示 “Hello World”。创建一个 web-app 目录并使它成为当前目录。进入 web-app 应用目录并编辑一个名为 main.go 的文件。

root@demohost:~# mkdir web-app
root@demohost:~# cd web-app/
root@demohost:~/web-app# vim.tiny main.go

package main
import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello %s", r.URL.Path[1:])
}

func main() {
    http.HandleFunc("/World", handler)
    http.ListenAndServe(":8080", nil)
}

使用下面的命令运行上面的 “Hello World” Go 程序。在浏览器中输入 http://127.0.0.1:8080/World 测试,你会在浏览器中看到 “Hello World”。

root@demohost:~/web-app# PORT=8080 go run main.go

下一步是将上面的应用在 docker 中容器化。因此我们会创建一个 dockerfile 文件,它会告诉 docker 如何容器化我们的 web 应用。

root@demohost:~/web-app# vim.tiny Dockerfile

# 得到最新的 golang docker 镜像
FROM golang:latest

# 在容器内部创建一个目录来存储我们的 web 应用,接着使它成为工作目录。
RUN mkdir -p /go/src/web-app
WORKDIR /go/src/web-app

# 复制 web-app 目录到容器中
COPY . /go/src/web-app

# 下载并安装第三方依赖到容器中
RUN go-wrapper download
RUN go-wrapper install

# 设置 PORT 环境变量
ENV PORT 8080

# 给主机暴露 8080 端口,这样外部网络可以访问你的应用
EXPOSE 8080

# 告诉 Docker 启动容器运行的命令
CMD ["go-wrapper", "run"]

构建/运行容器

使用下面的命令构建你的 Go web-app,你会在成功构建后获得确认。

root@demohost:~/web-app# docker build --rm -t web-app .
Sending build context to Docker daemon 3.584 kB
Step 1 : FROM golang:latest
latest: Pulling from library/golang
386a066cd84a: Already exists
75ea84187083: Pull complete
88b459c9f665: Pull complete
a31e17eb9485: Pull complete
1b272d7ab8a4: Pull complete
eca636a985c1: Pull complete
08158782d330: Pull complete
Digest: sha256:02718aef869a8b00d4a36883c82782b47fc01e774d0ac1afd434934d8ccfee8c
Status: Downloaded newer image for golang:latest
---> 9752d71739d2
Step 2 : RUN mkdir -p /go/src/web-app
---> Running in 9aef92fff9e8
---> 49936ff4f50c
Removing intermediate container 9aef92fff9e8
Step 3 : WORKDIR /go/src/web-app
---> Running in 58440a93534c
---> 0703574296dd
Removing intermediate container 58440a93534c
Step 4 : COPY . /go/src/web-app
---> 82be55bc8e9f
Removing intermediate container cae309ac7757
Step 5 : RUN go-wrapper download
---> Running in 6168e4e96ab1
+ exec go get -v -d
---> 59664b190fee
Removing intermediate container 6168e4e96ab1
Step 6 : RUN go-wrapper install
---> Running in e56f093b6f03
+ exec go install -v
web-app
---> 584cd410fdcd
Removing intermediate container e56f093b6f03
Step 7 : ENV PORT 8080
---> Running in 298e2a415819
---> c87fd2b43977
Removing intermediate container 298e2a415819
Step 8 : EXPOSE 8080
---> Running in 4f639a3790a7
---> 291167229d6f
Removing intermediate container 4f639a3790a7
Step 9 : CMD go-wrapper run
---> Running in 6cb6bc28e406
---> b32ca91bdfe0
Removing intermediate container 6cb6bc28e406
Successfully built b32ca91bdfe0

现在可以运行我们的 web-app 了,可以执行下面的命令。

root@demohost:~/web-app# docker run -p 8080:8080 --name="test" -d web-app
7644606b9af28a3ef1befd926f216f3058f500ffad44522c1d4756c576cfa85b

进入 http://localhost:8080/World 浏览你的 web 应用。你已经成功容器化了一个可重复的/确定性的 Go web 应用。使用下面的命令来启动、停止并检查容器的状态。

### 列出所有容器
root@demohost:~/ docker ps -a

### 使用 id 启动容器
root@demohost:~/ docker start CONTAINER_ID_OF_WEB_APP

### 使用 id 停止容器
root@demohost:~/ docker stop CONTAINER_ID_OF_WEB_APP

重新构建镜像

假设你正在开发 web 应用程序并在更改代码。现在要在更新代码后查看结果,你需要重新生成 docker 镜像、停止旧镜像并运行新镜像,并且每次更改代码时都要这样做。为了使这个过程自动化,我们将使用 docker 卷在主机和容器之间共享一个目录。这意味着你不必为在容器内进行更改而重新构建镜像。容器如何检测你是否对 web 程序的源码进行了更改?答案是有一个名为 “Gin” 的好工具 https://github.com/codegangsta/gin,它能检测是否对源码进行了任何更改,然后重建镜像/二进制文件并在容器内运行更新过代码的进程。

要使这个过程自动化,我们将编辑 Dockerfile 并安装 Gin 将其作为入口命令来执行。我们将开放 3030 端口(Gin 代理),而不是 8080。 Gin 代理将转发流量到 web 程序的 8080 端口。

root@demohost:~/web-app# vim.tiny Dockerfile

# 得到最新的 golang docker 镜像
FROM golang:latest

# 在容器内部创建一个目录来存储我们的 web 应用,接着使它称为工作目录。
RUN mkdir -p /go/src/web-app
WORKDIR /go/src/web-app

# 复制 web 程序到容器中
COPY . /go/src/web-app

# 下载并安装第三方依赖到容器中
RUN go get github.com/codegangsta/gin
RUN go-wrapper download
RUN go-wrapper install

# 设置 PORT 环境变量
ENV PORT 8080

# 给主机暴露 8080 端口,这样外部网络可以访问你的应用
EXPOSE 3030

# 启动容器时运行 Gin
CMD gin run

# 告诉 Docker 启动容器运行的命令
CMD ["go-wrapper", "run"]

现在构建镜像并启动容器:

root@demohost:~/web-app# docker build --rm -t web-app .

我们会在当前 web 程序的根目录下运行 docker,并通过暴露的 3030 端口链接 CWD (当前工作目录)到容器中的应用目录下。

root@demohost:~/web-app# docker run -p 3030:3030 -v `pwd`:/go/src/web-app --name="test" -d web-app

打开 http://localhost:3030/World, 你就能看到你的 web 程序了。现在如果你改变了任何代码,会在浏览器刷新后反映在你的浏览器中。

总结

就是这样,我们的 Go web 应用已经运行在 Ubuntu 16.04 Docker 容器中运行了!你可以通过使用 Go 框架来快速开发 API、网络应用和后端服务,从而扩展当前的网络应用。


via: http://linoxide.com/containers/setup-go-docker-deploy-application/

作者:Dwijadas Dey 译者:geekpi 校对:jasminepeng

本文由 LCTT 原创编译,Linux中国 荣誉推出

2016 年 11 月最后一天,Canonical 和 Docker 公司宣布了一个新的商务合作意向,承诺为 Ubuntu Linux 提供商业版 Docker 引擎的企业级支持和 SLA。

这两家公司将在 Ubuntu 平台上集成商业版 Docker 引擎,这样 Canonical 就可以一体化为其客户提供商业版 Docker 引擎和 Ubuntu Linux 系统的支持。

“通过我们的合作,将商业版 Docker 引擎带到了庞大的 Ubuntu 社区, 在敏捷性、移植性和安全性方面为用户提供了更多选择。”Docker 的商业发展和技术联盟副总裁 Nick Stinemates 说。

Ubuntu 的客户现在可以受益于 Docker 的官方支持

Docker 和 Canonical 之间的新合作将使 Ubuntu 客户得到 Docker 的官方支持,而目前其他的 Linux 发行版尚无此支持。因此, Docker 公司将会以 Snap 格式发布和维护新版本的商业版 Docker 引擎。

这些 Docker 维护的 Snap 软件包将由 Docker 公司推送回上游,Ubuntu 16.04 LTS 及其它支持 Snap 的 Linux 系统将可以直接访问由官方构建的 Docker 应用容器。

“在可伸缩容器运营方面,Ubuntu 和 Docker 的组合很流行,这次的合作意向将使我们的用户可以在商业版 Docker 引擎的 DevOps 产品化方面开辟一条更快、更容易的发展道路。”Canonical 的云联盟和商业发展副总裁 John Zannos 说。

据 Canonical 和 Docker 称,Ubuntu 在以容器为中心的 DevOps 平台环境中非常流行,所以在加快和保持维护 Docker 版本发布的需求方面日益增加。最新的 Snap 技术为 Ubuntu 上的新发布 Docker 软件提供了额外的安全保护。

通过几个点击即可在 “AWS 快速起步”和“Azure 市场”上高效搭建产品级 Docker 数据中心。

通过 AWS 快速起步的 CloudFormation 模板和在 Azure 市场上的预编译模板来部署 Docker 数据中心使得比以往在公有云基础设施下的部署企业级的 CaaS Docker 环境更加容易。

Docker 数据中心 CaaS 平台为各种规模的企业的敏捷应用部署提供了容器和集群的编排和管理,使之更简单、安全和可伸缩。使用新为 Docker 数据中心预编译的云模板,开发者和 IT 运维人员可以无缝的把容器化的应用迁移到亚马逊 EC2 或者微软的 Azure 环境而无需修改任何代码。现在,企业可以快速实现更高的计算和运营效率,可以通过短短几步操作实现支持 Docker 的容器管理和编排。

什么是 Docker 数据中心?

Docker 数据中心包括了 Docker 通用控制面板 Docker Universal Control Plane (UCP), Docker 可信注册库 Docker Trusted Registry (UTR)和 商用版 Docker 引擎 CS Docker Engine ,并带有与客户的应用服务等级协议相匹配的商业支持服务。

  • Docker 通用控制面板(UCP),一种企业级的集群管理方案,帮助客户通过单个管理面板管理整个集群
  • Docker 可信注册库(DTR), 一种镜像存储管理方案,帮助客户安全存储和管理 Docker 镜像
  • 商用版的 Docker 引擎

在 AWS 上快速布置 Docker 数据中心

秉承 Docker 与 AWS 最佳实践,参照 AWS 快速起步教程来,你可以在 AWS 云上快速部署 Docker 容器。Docker 数据中心快速起步基于模块化和可定制的 CloudFormation 模板,客户可以在其之上增加额外功能或者为自己的 Docker 部署修改模板。

架构

AWS Cloudformation 的安装过程始于创建 AWS 资源,这些 AWS 需要的资源包括:VPC、安全组、公有与私有子网、因特网网关、NAT 网关与 S3 bucket。

然后,AWS Cloudformation 启动第一个 UCP 控制器实例,紧接着,安装 Docker 引擎和 UCP 容器。它把第一个 UCP 控制器创建的根证书备份到 S3。一旦第一个 UCP 控制器成功运行,其他 UCP 控制器、UCP 集群节点和第一个 DTR 复制的进程就会被触发。和第一个 UCP 控制器节点类似,其他所有节点创建进程也都由商用版 Docker 引擎开始,然后安装并运行 UCP 和 DTR 容器以加入集群。两个弹性负载均衡器(ELB),一个分配给 UCP,另外一个为 DTR 服务,它们启动并自动完成配置来在两个可用区(AZ)之间提供弹性负载均衡。

除这些之外,如有需要,UCP 控制器和节点在 ASG 中启动并提供扩展功能。这种架构确保 UCP 和 DTR 两者都部署在两个 AZ 上以增强弹性与高可靠性。在公有或者私有 HostedZone 上,Route53 用来动态注册或者配置 UCP 和 DTR。

快速起步模板的核心功能如下:

  • 创建 VPC、不同 AZ 上的私有和公有子网、ELB、NAT 网关、因特网网关、自动伸缩组,它们全部基于 AWS 最佳实践
  • 为 DDC 创建一个 S3 bucket,其用于证书备份和 DTR 映像存储(DTR 需要额外配置)
  • 在客户的 VPC 范畴,跨多 AZ 部署 3 个 UCP 控制器
  • 创建预配置正常检测的 UCP ELB
  • 创建一个 DNS 记录并关联到 UCP ELB
  • 创建可伸缩的 UCP 节点集群
  • 在 VPC 范畴内,跨多 AZ 创建 3 个 DTR 副本
  • 创建一个预配置正常检测的 DTR
  • 创建一个 DNS 记录,并关联到 DTR ELB

在 AWS 使用 Docker 数据中心

  1. 登录 Docker Store 获取 30 天免费试用或者联系销售
  2. 确认之后,看到提示“Launch Stack”后,客户会被重定向到 AWS Cloudformation 入口
  3. 确认启动 Docker 的 AWS 区域
  4. 提供启动参数
  5. 确认并启动
  6. 启动完成之后,点击输出标签可以看到 UCP/DTR 的 URL、缺省用户名、密码和 S3 bucket 的名称

在 Azure 使用 Azure 市场的预编译模板部署

在 Azure 市场上,Docker 数据中心是一个预先编译的模板,客户可以在 Azure 横跨全球的数据中心即起即用。客户可以根据自己需求从 Azure 提供的各种 VM 中选择适合自己的 VM 部署 Docker 数据中心。

架构

Azure 部署过程始于输入一些基本用户信息,如 ssh 登录的管理员用户名(系统级管理员)和资源组名称。你可以把资源组理解为一组有生命周期和部署边界的资源集合。你可以在这个链接了解更多关于资源组的信息:<http://azure.microsoft.com/en-us/documentation/articles/resource-group-overview/> 。

下一步,输入集群详细信息,包括:UCP 控制器 VM 大小、控制器个数(缺省为 3 个)、UCP 节点 VM 大小、UCP 节点个数(缺省 1,最大值为 10)、DTR 节点 VM 大小、DTR 节点个数、虚拟网络名和地址(例如:10.0.0.1/19)。关于网络,客户可以配置 2 个子网:第一个子网分配给 UCP 控制器 ,第二个分配给 DTC 和 UCP 节点。

最后,点击 OK 完成部署。对于小集群,服务开通需要大约 15-19 分钟,大集群更久些。

如何在 Azure 部署

  1. 注册 Docker 数据中心 30 天试用许可或者联系销售
  2. 跳转到微软 Azure 市场的 Docker 数据中心
  3. 查看部署文档

通过注册获取 Docker 数据中心许可证开始,然后你就能够通过 AWS 或者 Azure 模板搭建自己的数据中心。

了解有关 Docker 的更多信息:


via: https://blog.docker.com/2016/06/docker-datacenter-aws-azure-cloud/

作者:Trisha McCanna 译者:firstadream 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

在这篇文章中,我们将考察一个 Node.js 开发原型,该原型用于从英国三个主要折扣网店查找“Raspberry PI Zero”的库存。

我写好了代码,然后经过一晚的鼓捣把它部署在 Aure 上的 Ubuntu 虚拟机上。Docker 和 docker-compose 工具使得部署和更新过程非常快。

还记得链接指令(link)吗?

如果你已经阅读过 Hands-on Docker tutorial,那么你应该已经可以使用命令行链接 Docker 容器。通过命令行将 Node.js 的计数器链接到 Redis 服务器,其命令可能如下所示:

$ docker run -d -P --name redis1
$ docker run -d hit_counter -p 3000:3000 --link redis1:redis

现在假设你的应用程序分为三层:

  • Web 前端
  • 处理长时间运行任务的批处理层
  • Redis 或者 mongo 数据库

通过--link的显式链接只是管理几个容器是可以的,但是可能会因为我们向应用程序添加更多层或容器而失控。

加入 docker-compose

Docker Compose logo

docker-compose 工具是标准 Docker 工具箱的一部分,也可以单独下载。 它提供了一组丰富的功能,通过纯文本 YAML 文件配置所有应用程序的部件。

上面的例子看起来像这样:

version: "2.0"
services:
  redis1:
    image: redis
  hit_counter:
    build: ./hit_counter
    ports:
     - 3000:3000

从 Docker 1.10 开始,我们可以利用网络覆盖(network overlays)来帮助我们在多个主机上进行扩展。 在此之前,链接仅能工作在单个主机上。 docker-compose scale 命令可以用来在需要时带来更多的计算能力。

查看 docker.com 上的 docker-compose 参考

 真实工作示例:Raspberry PI 库存警示

新的 Raspberry PI Zero v1.3 图片,由 Pimoroni 提供

Raspberry PI Zero 嗡嗡作响 - 它是一个极小的微型计算机,具有 1GHz CPU 和 512MB RAM,可以运行完整的Linux、Docker、Node.js、Ruby 和其他许多流行的开源工具。 PI Zero 最好的优点之一就是它成本只有 5 美元。 这也意味着它销售的速度非常之快。

如果你想在 PI 上尝试 Docker 和 Swarm,请查看下面的教程:Docker Swarm on the PI Zero

原始网站:whereismypizero.com

我发现一个网页,它使用屏幕抓取以找出 4-5 个最受欢迎的折扣网店是否有库存。

  • 网站包含静态 HTML 网页
  • 向每个折扣网店发出一个 XMLHttpRequest 访问 /public/api/
  • 服务器向每个网店发出 HTTP 请求并执行抓屏

每一次对 /public/api/ 的调用,其执行花 3 秒钟,而使用 Apache Bench(ab),我每秒只能完成 0.25 个请求。

重新发明轮子

零售商似乎并不介意 whereismypizero.com 抓取他们的网站的商品库存信息,所以我开始从头写一个类似的工具。 我尝试通过缓存和解耦 web 层来处理更多的抓取请求。 Redis 是执行这项工作的完美工具。 它允许我设置一个自动过期的键/值对(即一个简单的缓存),还可以通过 pub/sub 在 Node.js 进程之间传输消息。

复刻或者追踪放在 github 上的代码: alexellis/pizerostock

如果之前使用过 Node.js,你肯定知道它是单线程的,并且任何 CPU 密集型任务,如解析 HTML 或 JSON 都可能导致速度放缓。一种缓解这种情况的方法是使用一个工作进程和 Redis 消息通道作为它和 web 层之间的连接组织。

  • Web 层

    • 使用 200 代表缓冲命中(该商店的 Redis 键存在)
    • 使用 202 代表高速缓存未命中(该商店的 Redis 键不存在,因此发出消息)
    • 因为我们只是读一个 Redis 键,响应时间非常快。
  • 库存抓取器

    • 执行 HTTP 请求
    • 用于在不同类型的网店上抓屏
    • 更新 Redis 键的缓存失效时间为 60 秒
    • 另外,锁定一个 Redis 键,以防止对网店过多的 HTTP 请求。
version: "2.0"  
services:  
  web:
    build: ./web/
    ports:
     - "3000:3000"
  stock_fetch:
    build: ./stock_fetch/
  redis:
    image: redis

来自示例的 docker-compose.yml 文件

一旦本地正常工作,再向 Azure 的 Ubuntu 16.04 镜像云部署就轻车熟路,只花了不到 5 分钟。 我登录、克隆仓库并键入docker-compose up -d, 这就是所有的工作 - 快速实现整个系统的原型不会比这几个步骤更多。 任何人(包括 whereismypizero.com 的所有者)只需两行命令就可以部署新解决方案:

$ git clone https://github.com/alexellis/pi_zero_stock
$ docker-compose up -d

更新网站很容易,只需要一个git pull命令,然后执行docker-compose up -d命令,该命令需要带上--build参数。

如果你仍然手动链接你的 Docker 容器,请自己或使用如下我的代码尝试 Docker Compose:

复刻或者追踪在 github 上的代码: alexellis/pizerostock

一睹测试网站芳容

目前测试网站使用 docker-compose 部署:stockalert.alexellis.io

预览于 2016 年 5 月 16 日


via: http://blog.alexellis.io/rapid-prototype-docker-compose/

作者:Alex Ellis 译者:firstadream 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

这篇文章基于我之前的文章 .NET Core 入门。首先,我把 RESTful API 从 .NET Core RC1 升级到了 .NET Core 1.0,然后,我增加了对 Docker 的支持并描述了如何在 Linux 生产环境里托管它。

我是首次接触 Docker 并且距离成为一名 Linux 高手还有很远的一段路程。因此,这里的很多想法是来自一个新手。

安装

按照 https://www.microsoft.com/net/core 上的介绍在你的电脑上安装 .NET Core 。这将会同时在 Windows 上安装 dotnet 命令行工具以及最新的 Visual Studio 工具。

源代码

你可以直接到 GitHub 上找最到最新完整的源代码。

转换到 .NET CORE 1.0

自然地,当我考虑如何把 API 从 .NET Core RC1 升级到 .NET Core 1.0 时想到的第一个求助的地方就是谷歌搜索。我是按照下面这两条非常全面的指导来进行升级的:

当你迁移代码的时候,我建议仔细阅读这两篇指导,因为我在没有阅读第一篇指导的情况下又尝试浏览第二篇,结果感到非常迷惑和沮丧。

我不想描述细节上的改变因为你可以看 GitHub 上的提交。这儿是我所作改变的总结:

  • 更新 global.jsonproject.json 上的版本号
  • 删除 project.json 上的废弃章节
  • 使用轻型 ControllerBase 而不是 Controller, 因为我不需要与 MVC 视图相关的方法(这是一个可选的改变)。
  • 从辅助方法中去掉 Http 前缀,比如:HttpNotFound -> NotFound
  • LogVerbose -> LogTrace
  • 名字空间改变: Microsoft.AspNetCore.*
  • Startup 中使用 SetBasePath(没有它 appsettings.json 将不会被发现)
  • 通过 WebHostBuilder 来运行而不是通过 WebApplication.Run 来运行
  • 删除 Serilog(在写文章的时候,它不支持 .NET Core 1.0)

唯一令我真正头疼的事是需要移动 Serilog。我本可以实现自己的文件记录器,但是我删除了文件记录功能,因为我不想为了这次操作在这件事情上花费精力。

不幸的是,将有大量的第三方开发者扮演追赶 .NET Core 1.0 的角色,我非常同情他们,因为他们通常在休息时间还坚持工作但却依旧根本无法接近靠拢微软的可用资源。我建议阅读 Travis Illig 的文章 .NET Core 1.0 发布了,但 Autofac 在哪儿?这是一篇关于第三方开发者观点的文章。

做了这些改变以后,我可以从 project.json 目录恢复、构建并运行 dotnet,可以看到 API 又像以前一样工作了。

通过 Docker 运行

在我写这篇文章的时候, Docker 只能够在 Linux 系统上工作。在 Windows 系统和 OS X 上有 beta 支持 Docker,但是它们都必须依赖于虚拟化技术,因此,我选择把 Ubuntu 14.04 当作虚拟机来运行。如果你还没有安装过 Docker,请按照指导来安装。

我最近阅读了一些关于 Docker 的东西,但我直到现在还没有真正用它来干任何事。我假设读者还没有关于 Docker 的知识,因此我会解释我所使用的所有命令。

HELLO DOCKER

在 Ubuntu 上安装好 Docker 之后,我所进行的下一步就是按照 https://www.microsoft.com/net/core#docker 上的介绍来开始运行 .NET Core 和 Docker。

首先启动一个已安装有 .NET Core 的容器。

docker run -it microsoft/dotnet:latest

-it 选项表示交互,所以你执行这条命令之后,你就处于容器之内了,可以如你所希望的那样执行任何 bash 命令。

然后我们可以执行下面这五条命令来在 Docker 内部运行起来微软 .NET Core 控制台应用程序示例。

mkdir hwapp
cd hwapp
dotnet new
dotnet restore
dotnet run

你可以通过运行 exit 来离开容器,然后运行 Docker ps -a 命令,这会显示你创建的那个已经退出的容器。你可以通过上运行命令 Docker rm <container_name> 来清除容器。

挂载源代码

我的下一步骤是使用和上面相同的 microsoft/dotnet 镜像,但是将为我们的应用程序以数据卷的方式挂载上源代码。

首先签出有相关提交的仓库:

git clone https://github.com/niksoper/aspnet5-books.git
cd aspnet5-books/src/MvcLibrary
git checkout dotnet-core-1.0

现在启动一个容器来运行 .NET Core 1.0,并将源代码放在 /book 下。注意更改 /path/to/repo 这部分文件来匹配你的电脑:

docker run -it \
-v /path/to/repo/aspnet5-books/src/MvcLibrary:/books \
microsoft/dotnet:latest

现在你可以在容器中运行应用程序了!

cd /books
dotnet restore
dotnet run

作为一个概念性展示这的确很棒,但是我们可不想每次运行一个程序都要考虑如何把源代码安装到容器里。

增加一个 DOCKERFILE

我的下一步骤是引入一个 Dockerfile,这可以让应用程序很容易在自己的容器内启动。

我的 Dockerfile 和 project.json 一样位于 src/MvcLibrary 目录下,看起来像下面这样:

FROM microsoft/dotnet:latest

# 为应用程序源代码创建目录
RUN mkdir -p /usr/src/books
WORKDIR /usr/src/books

# 复制源代码并恢复依赖关系
COPY . /usr/src/books
RUN dotnet restore

# 暴露端口并运行应用程序
EXPOSE 5000
CMD [ "dotnet", "run" ]

严格来说,RUN mkdir -p /usr/src/books 命令是不需要的,因为 COPY 会自动创建丢失的目录。

Docker 镜像是按层建立的,我们从包含 .NET Core 的镜像开始,添加另一个从源代码生成应用程序,然后运行这个应用程序的层。

添加了 Dockerfile 以后,我通过运行下面的命令来生成一个镜像,并使用生成的镜像启动一个容器(确保在和 Dockerfile 相同的目录下进行操作,并且你应该使用自己的用户名)。

docker build -t niksoper/netcore-books .
docker run -it niksoper/netcore-books

你应该看到程序能够和之前一样的运行,不过这一次我们不需要像之前那样安装源代码,因为源代码已经包含在 docker 镜像里面了。

暴露并发布端口

这个 API 并不是特别有用,除非我们需要从容器外面和它进行通信。 Docker 已经有了暴露和发布端口的概念,但这是两件完全不同的事。

据 Docker 官方文档

EXPOSE 指令通知 Docker 容器在运行时监听特定的网络端口。EXPOSE 指令不能够让容器的端口可被主机访问。要使可被访问,你必须通过 -p 标志来发布一个端口范围或者使用 -P 标志来发布所有暴露的端口

EXPOSE 指令只是将元数据添加到镜像上,所以你可以如文档中说的认为它是镜像消费者。从技术上讲,我本应该忽略 EXPOSE 5000 这行指令,因为我知道 API 正在监听的端口,但把它们留下很有用的,并且值得推荐。

在这个阶段,我想直接从主机访问这个 API ,因此我需要通过 -p 指令来发布这个端口,这将允许请求从主机上的端口 5000 转发到容器上的端口 5000,无论这个端口是不是之前通过 Dockerfile 暴露的。

docker run -d -p 5000:5000 niksoper/netcore-books

通过 -d 指令告诉 docker 在分离模式下运行容器,因此我们不能看到它的输出,但是它依旧会运行并监听端口 5000。你可以通过 docker ps 来证实这件事。

因此,接下来我准备从主机向容器发起一个请求来庆祝一下:

curl http://localhost:5000/api/books

它不工作。

重复进行相同 curl 请求,我看到了两个错误:要么是 curl: (56) Recv failure: Connection reset by peer,要么是 curl: (52) Empty reply from server

我返回去看 docker run 的文档,然后再次检查我所使用的 -p 选项以及 Dockerfile 中的 EXPOSE 指令是否正确。我没有发现任何问题,这让我开始有些沮丧。

重新振作起来以后,我决定去咨询当地的一个 Scott Logic DevOps 大师 - Dave Wybourn(也在这篇 Docker Swarm 的文章里提到过),他的团队也曾遇到这个实际问题。这个问题是我没有配置过 Kestral,这是一个全新的轻量级、跨平台 web 服务器,用于 .NET Core 。

默认情况下, Kestrel 会监听 http://localhost:5000。但问题是,这儿的 localhost 是一个回路接口。

维基百科

在计算机网络中,localhost 是一个代表本机的主机名。本地主机可以通过网络回路接口访问在主机上运行的网络服务。通过使用回路接口可以绕过任何硬件网络接口。

当运行在容器内时这是一个问题,因为 localhost 只能够在容器内访问。解决方法是更新 Startup.cs 里的 Main 方法来配置 Kestral 监听的 URL:

public static void Main(string[] args)
{
  var host = new WebHostBuilder()
    .UseKestrel()
    .UseContentRoot(Directory.GetCurrentDirectory())
    .UseUrls("http://*:5000") // 在所有网络接口上监听端口 5000
    .UseIISIntegration()
    .UseStartup<Startup>()
    .Build();

  host.Run();
}

通过这些额外的配置,我可以重建镜像,并在容器中运行应用程序,它将能够接收来自主机的请求:

docker build -t niksoper/netcore-books .
docker run -d -p 5000:5000 niksoper/netcore-books
curl -i http://localhost:5000/api/books

我现在得到下面这些相应:

HTTP/1.1 200 OK
Date: Tue, 30 Aug 2016 15:25:43 GMT
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Kestrel

[{"id":"1","title":"RESTful API with ASP.NET Core MVC 1.0","author":"Nick Soper"}]

在产品环境中运行 KESTREL

微软的介绍

Kestrel 可以很好的处理来自 ASP.NET 的动态内容,然而,网络服务部分的特性没有如 IIS,Apache 或者 Nginx 那样的全特性服务器那么好。反向代理服务器可以让你不用去做像处理静态内容、缓存请求、压缩请求、SSL 端点这样的来自 HTTP 服务器的工作。

因此我需要在我的 Linux 机器上把 Nginx 设置成一个反向代理服务器。微软介绍了如何发布到 Linux 生产环境下的指导教程。我把说明总结在这儿:

  1. 通过 dotnet publish 来给应用程序产生一个自包含包。
  2. 把已发布的应用程序复制到服务器上
  3. 安装并配置 Nginx(作为反向代理服务器)
  4. 安装并配置 supervisor(用于确保 Nginx 服务器处于运行状态中)
  5. 安装并配置 AppArmor(用于限制应用的资源使用)
  6. 配置服务器防火墙
  7. 安全加固 Nginx(从源代码构建和配置 SSL)

这些内容已经超出了本文的范围,因此我将侧重于如何把 Nginx 配置成一个反向代理服务器。自然地,我通过 Docker 来完成这件事。

在另一个容器中运行 NGINX

我的目标是在第二个 Docker 容器中运行 Nginx 并把它配置成我们的应用程序容器的反向代理服务器。

我使用的是来自 Docker Hub 的官方 Nginx 镜像。首先我尝试这样做:

docker run -d -p 8080:80 --name web nginx

这启动了一个运行 Nginx 的容器并把主机上的 8080 端口映射到了容器的 80 端口上。现在在浏览器中打开网址 http://localhost:8080 会显示出 Nginx 的默认登录页面。

现在我们证实了运行 Nginx 是多么的简单,我们可以关闭这个容器。

docker rm -f web

把 NGINX 配置成一个反向代理服务器

可以通过像下面这样编辑位于 /etc/nginx/conf.d/default.conf 的配置文件,把 Nginx 配置成一个反向代理服务器:

server {
  listen 80;

  location / {
    proxy_pass http://localhost:6666;
  }
}

通过上面的配置可以让 Nginx 将所有对根目录的访问请求代理到 http://localhost:6666。记住这里的 localhost 指的是运行 Nginx 的容器。我们可以在 Nginx容器内部利用卷来使用我们自己的配置文件:

docker run -d -p 8080:80 \
-v /path/to/my.conf:/etc/nginx/conf.d/default.conf \
nginx

注意:这把一个单一文件从主机映射到容器中,而不是一个完整目录。

在容器间进行通信

Docker 允许内部容器通过共享虚拟网络进行通信。默认情况下,所有通过 Docker 守护进程启动的容器都可以访问一种叫做“桥”的虚拟网络。这使得一个容器可以被另一个容器在相同的网络上通过 IP 地址和端口来引用。

你可以通过 监测 inspect 容器来找到它的 IP 地址。我将从之前创建的 niksoper/netcore-books 镜像中启动一个容器并 监测 inspect 它:

docker run -d -p 5000:5000 --name books niksoper/netcore-books
docker inspect books

我们可以看到这个容器的 IP 地址是 "IPAddress": "172.17.0.3"

所以现在如果我创建下面的 Nginx 配置文件,并使用这个文件启动一个 Nginx 容器, 它将代理请求到我的 API :

server {
  listen 80;

  location / {
    proxy_pass http://172.17.0.3:5000;
  }
}

现在我可以使用这个配置文件启动一个 Nginx 容器(注意我把主机上的 8080 端口映射到了 Nginx 容器上的 80 端口):

docker run -d -p 8080:80 \
-v ~/dev/nginx/my.nginx.conf:/etc/nginx/conf.d/default.conf \
nginx

一个到 http://localhost:8080 的请求将被代理到应用上。注意下面 curl 响应的 Server 响应头:

DOCKER COMPOSE

在这个地方,我为自己的进步而感到高兴,但我认为一定还有更好的方法来配置 Nginx,可以不需要知道应用程序容器的确切 IP 地址。另一个当地的 Scott Logic DevOps 大师 Jason Ebbin 在这个地方进行了改进,并建议使用 Docker Compose

概况描述一下,Docker Compose 使得一组通过声明式语法互相连接的容器很容易启动。我不想再细说 Docker Compose 是如何工作的,因为你可以在之前的文章中找到。

我将通过一个我所使用的 docker-compose.yml 文件来启动:

version: '2'
services:
    books-service:
        container_name: books-api
        build: .

    reverse-proxy:
        container_name: reverse-proxy
        image: nginx
        ports:
         - "9090:8080"
        volumes:
         - ./proxy.conf:/etc/nginx/conf.d/default.conf

这是版本 2 语法,所以为了能够正常工作,你至少需要 1.6 版本的 Docker Compose。

这个文件告诉 Docker 创建两个服务:一个是给应用的,另一个是给 Nginx 反向代理服务器的。

BOOKS-SERVICE

这个与 docker-compose.yml 相同目录下的 Dockerfile 构建的容器叫做 books-api。注意这个容器不需要发布任何端口,因为只要能够从反向代理服务器访问它就可以,而不需要从主机操作系统访问它。

REVERSE-PROXY

这将基于 nginx 镜像启动一个叫做 reverse-proxy 的容器,并将位于当前目录下的 proxy.conf 文件挂载为配置。它把主机上的 9090 端口映射到容器中的 8080 端口,这将允许我们在 http://localhost:9090 上通过主机访问容器。

proxy.conf 文件看起来像下面这样:

server {
    listen 8080;

    location / {
      proxy_pass http://books-service:5000;
    }
}

这儿的关键点是我们现在可以通过名字引用 books-service,因此我们不需要知道 books-api 这个容器的 IP 地址!

现在我们可以通过一个运行着的反向代理启动两个容器(-d 意味着这是独立的,因此我们不能看到来自容器的输出):

docker compose up -d

验证我们所创建的容器:

docker ps

最后来验证我们可以通过反向代理来控制该 API :

curl -i http://localhost:9090/api/books

怎么做到的?

Docker Compose 通过创建一个新的叫做 mvclibrary_default 的虚拟网络来实现这件事,这个虚拟网络同时用于 books-apireverse-proxy 容器(名字是基于 docker-compose.yml 文件的父目录)。

通过 docker network ls 来验证网络已经存在:

你可以使用 docker network inspect mvclibrary_default 来看到新的网络的细节:

注意 Docker 已经给网络分配了子网:"Subnet": "172.18.0.0/16"/16 部分是无类域内路由选择(CIDR),完整的解释已经超出了本文的范围,但 CIDR 只是表示 IP 地址范围。运行 docker network inspect bridge 显示子网:"Subnet": "172.17.0.0/16",因此这两个网络是不重叠的。

现在用 docker inspect books-api 来确认应用程序的容器正在使用该网络:

注意容器的两个别名("Aliases")是容器标识符(3c42db680459)和由 docker-compose.yml 给出的服务名(books-service)。我们通过 books-service 别名在自定义 Nginx 配置文件中来引用应用程序的容器。这本可以通过 docker network create 手动创建,但是我喜欢用 Docker Compose,因为它可以干净简洁地将容器创建和依存捆绑在一起。

结论

所以现在我可以通过几个简单的步骤在 Linux 系统上用 Nginx 运行应用程序,不需要对主机操作系统做任何长期的改变:

git clone https://github.com/niksoper/aspnet5-books.git
cd aspnet5-books/src/MvcLibrary
git checkout blog-docker
docker-compose up -d
curl -i http://localhost:9090/api/books

我知道我在这篇文章中所写的内容不是一个真正的生产环境就绪的设备,因为我没有写任何有关下面这些的内容,绝大多数下面的这些主题都需要用单独一篇完整的文章来叙述。

  • 安全考虑比如防火墙和 SSL 配置
  • 如何确保应用程序保持运行状态
  • 如何选择需要包含的 Docker 镜像(我把所有的都放入了 Dockerfile 中)
  • 数据库 - 如何在容器中管理它们

对我来说这是一个非常有趣的学习经历,因为有一段时间我对探索 ASP.NET Core 的跨平台支持非常好奇,使用 “Configuratin as Code” 的 Docker Compose 方法来探索一下 DevOps 的世界也是非常愉快并且很有教育意义的。

如果你对 Docker 很好奇,那么我鼓励你来尝试学习它 或许这会让你离开舒适区,不过,有可能你会喜欢它?


via: http://blog.scottlogic.com/2016/09/05/hosting-netcore-on-linux-with-docker.html

作者:Nick Soper 译者:ucasFL 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出