该工具的主要作用就是用于配置/管理/共享和安装应用程序的 Docker 客户端插件
1. 背景介绍
本部分主要介绍了关于 docker-app 工具的背景和开发原因
咳咳咳咳咳咳,我们很熟悉且清楚的知道,通过在 docker-compose.yml 文件中对一组服务进行描述,就可以在 Docker 上用一条命令轻松的启动一个简单的单服务应用程序或一个复杂的多服务应用程序。这种易用性使得 Docker Compose 非常适合开发团队快速构建项目环境以及测试环境的搭建。目前,GitHub 上有超过 3.5k 多个项目在使用 Docker Compose 了。
随着时间的推移,Compose 不断发展并添加了许多功能可以将相同的应用程序部署到生产环境时提供帮助。例如,指定大量副本、内存资源限制或自定义系统日志服务器,但这些属性可能会跟您自己的环境有所差异。有许多不同的策略来解决这个问题,但是最常见的就是依赖于复制和粘贴。例如,为在不同环境中运行的同一应用程序维护多个 Compose 文件是相当常见的,但这会导致了两个问题:
- 通过 DockerHub 官方仓库,我们一直都在分享 Docker 镜像,但却没有一个很好的方法来共享使用它们的多服务应用程序;
- 开发人员和运维人员很难围绕同一个 Compose 文件进行协作,并在产品部署到生产环境或者客户环境之前捕获配置问题;
- 因为服务部署往往不是一个容器可以解决的,所以需要搭配多个容器同时使用,怎么样便捷、合理的进行部署就是一个很大的问题;
解决上述问题的一种方法就是通过构建一个与 Compose 相辅相成的工具来使它更容易用于共享和协作。需要注意的是,现在这个项目还属于实验性阶段,还有很多工作正在进行中,所以不建议再生产环境中使用。
2. 工具安装
安装方法比较通用,基本都是这个套路
在最新的版本中 Docker App 已经变成了一个 docker 内置的命令行插件,它将 docker 命令扩展为 app 子命令。 因为现在还是在实验阶段,所以启动该功能的话,需要 docker 版本在 19.03.0 以更高版本中设置环境变量 EXPERIMENTAL=true 才可以使用。
- [1] 安装方式 - MacOS
# Download Mac OS Tarball $ export OSTYPE="$(uname | tr A-Z a-z)" $ curl -fsSL --output "/tmp/docker-app-${OSTYPE}.tar.gz" "https://github.com/docker/app/releases/download/v0.8.0/docker-app-${OSTYPE}.tar.gz" $ tar xf "/tmp/docker-app-${OSTYPE}.tar.gz" -C /tmp/ # Install as a Docker CLI plugin $ mkdir -p ~/.docker/cli-plugins $ cp "/tmp/docker-app-plugin-${OSTYPE}" ~/.docker/cli-plugins/docker-app
- [2] 安装方式 - Windows
# Download Windows Tarball $ Invoke-WebRequest -Uri https://github.com/docker/app/releases/download/v0.8.0/docker-app-windows.tar.gz -OutFile docker-app.tar.gz -UseBasicParsing $ tar xf "docker-app.tar.gz" # Install as a Docker CLI plugin $ New-Item -ItemType Directory -Path ~/.docker/cli-plugins -ErrorAction SilentlyContinue $ cp docker-app-plugin-windows.exe ~/.docker/cli-plugins/docker-app.exe
- [3] 命令使用
3. 工具使用
易于在不同团队和不同环境之间共享和管理
Docker App 是在 2018 年 DockerCon 美国大会上简要介绍的一款新工具,其主要作用就是使 Compose 应用程序更易于在不同团队和不同环境之间共享和管理,并可在Docker Hub上共享。主要功能如下所示:
- 使用元数据(metadata)和参数扩展(parameters)来辅助Compose使用
- 在多种环境(Development/QA/Staging/Production)中可重用相同的Compose应用程序
- 与容器镜像(images)拥有相同的工作流,支持Push/Pull/Signing等操作
- 完全符合CNAB(Cloud Native Application Bundle)标准
- 完全支持Docker Contexts
- [1] 什么是 CNAB 标准
CNAB 是一个开源的、与云无关的规范,用于打包和运行分布式应用程序,旨在解决其中的存在的问题。CNAB 将跨不同工具链的多服务分布式应用程序的管理统一为一种单一的、一体化的打包格式。
Docker App 的最新版本就是一个实现当前 CNAB 规范的工具,而关于 CNAB 规范的更多详情可以在官方网站 cnab.io 上找到。这意味着它既可以为 Compose 构建 CNAB 包(可以与任何其他 CNAB 客户端一起使用),也可以安装、升级和卸载任何其他 CNAB 包。
- [2] 在 DockerHub 上共享 CNAB 包
单独的 Compose 文件的局限在于它们无法在 Docker Hub 上进行共享。Docker App 很好的解决了这个问题。这是一个简单的 Docker 应用程序,运行它将启动了一个非常简单的 hello world 应用程序。
# 必须v3.2版本+才能用 # docker-compose.yml version: "3.6" services: hello: image: hashicorp/http-echo command: ["-text", "${text}"] ports: - ${port}:5678
通过 docker app init 命令已经上述的 docker-compose.yml 文件初始化生成其他配置文件。
# 初始化生成其他配置文件 $ docker app init --compose-file docker-compose.yml hello Created "hello.dockerapp" # 得到如下目录结构 $ tree . ├── docker-compose.yml └── hello.dockerapp ├── docker-compose.yml # 基础compose文件 ├── metadata.yml # 该compose镜像的相关信息 └── parameters.yml # compose文件中的参数对应值
我们需要根据实际情况,补全上述 metadata.yml 和 parameters.yml 文件中的内容,其实更加完整。
# metadata.yml version: 0.1.0 name: hello description: A simple nginx text server maintainers: - name: escape email: [email protected] # parameters.yml port: 5678 text: hello development
现在,我们就可以构建一个该镜像包并在 DockerHub 上共享、分享它。
# 本地Build镜像 $ docker app build . -f hello.dockerapp -t escape/nginx_test:0.1.0 [+] Building 0.7s (6/6) FINISHED (...) (Build output) sha256:4a492748ae55170daadd1ddfff4db30e0ef3d38bf0f57a913512caa323e140de # 上传到我们自己的HubDocker仓库下面 $ docker app push escape/nginx_test:0.1.0 # 镜像加速(换命) https://github.com/Azure/container-service-for-azure-china/blob/master/aks/README.md#22-container-registry-proxy
Compose 文件中的所有信息都存储在 DockerHub 上的 CNAB 包中。您可能注意到了,它也是参数化的,因此可以在运行时替换它的值来满足部署要求。我们也可以直接从 DockerHub 安装应用程序。
# 查看远程镜像信息 $ docker app image inspect escape/nginx_test:0.1.0 --pretty # 拉去远程并运行容器 $ docker app run --name nginx escape/nginx_test:0.1.0 --set ports=8080
后续操作相关命令,实例说明。
# 列出正在运行的APP程序 $ docker app ls RUNNING APP APP NAME LAST ACTION RESULT CREATED nginx hello-world (0.1.0) install success About a minute ago # 移除运行的APP程序 $ docker app rm nginx Removing service nginx Removing network nginx_default
4. 调用方式
我们可以直接调用远程主机上面的 docker 引擎来部署服务。
虽然我们可以通过 docker-compose 工具快速搭建一套开发环境,但是首先我们需要在操作系统上安装和部署 docker 的容器引擎。而为了应对远程部署这样的问题,docker-compose 工具支持通过 DOCKER_HOST 环境变量和 -H/–host 命令行的方式来远程调用远程计算器上面的 docker 容器引擎。
我们定义一个 Compose 文件,该文件分为两项服务,前端运行 nginx 代理,该代理会将 HTTP 请求转发到简单的 Go 应用服务器。项目结构和对应的配置文件,我们可以看下面内容。
# 目录结构 $ tree hello-docker hello-docker ├── backend │ ├── Dockerfile │ └── main.go ├── docker-compose.yml ├── frontend ├── Dockerfile └── nginx.conf
# docker-compose.yml version: "3.6" services: frontend: build: frontend ports: – 8080:80 depends_on: – backend backend: build: backend
可以通过如下命令,在本地主机上运行。按照 docker-compose.yml 中的描述,检查所有容器都在运行,并且前端服务容器的端口 80 已映射到 localhost 的 8080 端口。
$ cd hello-docker/ $ docker-compose up -d Creating network "hello-docker_default" with the default driver Creating hello-docker_backend_1 … done Creating hello-docker_frontend_1 … done $ curl localhost:8080 ## . ## ## ## == ## ## ## ## ## === /"""""""""""""""""___/ === { / ===- ______ O __/ __/ ___________/ Hello from Docker!
这里主要说的是,如果运行在远程主机上。远程 Docker 主机是我们本地网络内部或外部的机器,该机器正在运行 Docker 服务并提供有用于查询 Docker 引擎 API 的端口。在开启 SSH 访问权限的前提下,可以通过以下几种方式将示例应用程序部署在远程主机上。
- [1] SSH 登录远程主机部署
# 那为什么不直接登录远程主机部署呢? $ scp -r hello-docker [email protected]:/path/to/src $ ssh [email protected] $ pip install docker-compose $ cd /path/to/src/hello-docker $ docker-compose up -d
- [2] 使用 DOCKER_HOST 环境变量
# DOCKER_HOST或者-H/–host $ cd hello-docker $ DOCKER_HOST="ssh://[email protected]" docker-compose up -d
- [3] 设置 docker contexts 配置
# Docker上下文是在不同部署目标之间自动切换的有效方法 $ docker context ls NAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR remote ssh://[email protected] $ cd hello-docker $ docker-compose ‐‐context remote up -d
Docker 上下文是一种为 Docker API 端点提供名称并存储该信息以供以后使用的机制。如文档所示,可以使用 Docker CLI 轻松管理 Docker 上下文。最新版本的 docker-compose 现在支持使用上下文来访问 Docker API 端点。这意味着我们可以运行 docker-compose 并指定上下文以自动控制远程主机。如果未指定上下文,则 docker-compose 将使用当前上下文,就像 Docker CLI 一样。
- 创建并使用 context 来连接远程主机
# 首先创建一个上下文来保存到它的连接路径 $ docker context create remote ‐‐docker "host=ssh://[email protected]" remote Successfully created context "remote" # 查看主机的上下本设置列表 $ docker context ls NAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR default * Current DOCKER_HOST… unix:///var/run/docker.sock swarm remote ssh://[email protected] $ docker ‐‐context remote ps CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES
# 设置为docker默认的上下文 $ docker context use remote remote Current context is now "remote" # 查看主机的上下本设置列表 $ docker context ls NAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR default Current DOCKER_HOST … unix:///var/run/docker.sock swarm remote * ssh://[email protected]
- 在 docker-compose 中使用 context
# 通过上下文来访问远程主机 $ docker-compose ‐‐context remote up -d /tmp/_MEI4HXgSK/paramiko/client.py:837: UserWarning: Unknown ssh-ed25519 host key for 10.0.0.52: b'047f5071513cab8c00d7944ef9d5d1fd' Creating network "hello-docker_default" with the default driver Creating hello-docker_backend_1 … done Creating hello-docker_frontend_1 … done # 查看远程主机运行的服务 $ docker ‐‐context remote ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ddbb380635aa hello-docker_frontend "nginx -g 'daemon of…" 24 seconds ago Up 23 seconds 0.0.0.0:8080->80/tcp hello-docker_web_1 872c6a55316f hello-docker_backend "/usr/local/bin/back…" 25 seconds ago Up 24 seconds hello-docker_backend_1
许多开发人员可能需要在多个开发/测试环境之间进行切换,现在通过在 docker-compose 中使用上下文,可以轻松实现所有这些部署。现在我们尝试在多个 Docker 引擎之间进行上下文切换,为此我们定义了三个目标,下表显示了上下文到 docker 目标的映射。
- 运行本地 Docker 引擎的本地主机
- 通过 ssh 访问的远程主机
- 一个 Docker-in-Docker 容器充当另一个远程主机
Target Environment | Context name | API endpoint |
---|---|---|
localhost | default | unix:///var/run/docker.sock |
remote-host | remote | ssh://[email protected] |
docker-in-docker | docker | tcp://127.0.0.1:2375 |
# run a Docker-in-Docker container $ docker run ‐‐rm -d -p "2375:2375" ‐‐privileged -e "DOCKER_TLS_CERTDIR=" ‐‐name dind docker:19.03.3-dind ed92bc991bade2d41cab08b8c070c70b788d8ecf9dffc89e8c6379187aed9cdc # look container is running $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ed92bc991bad docker:19.03.3-dind "dockerd-entrypoint.…" 17 seconds ago Up 15 seconds 0.0.0.0:2375->2375/tcp, 2376/tcp dind # create a new context 'dind' to easily target the container $ docker context create dind ‐‐docker "host=tcp://127.0.0.1:2375" ‐‐default-stack-orchestrator swarm dind Successfully created context "dind" # lock docker context list $ docker context ls NAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR default * Current DOCKER_HOST … unix:///var/run/docker.sock swarm remote ssh://[email protected] swarm
# 切换当前上下文为dind $ docker context use dind dind Current context is now "dind" # 启动服务 $ docker-compose up -d Creating network "hello-docker_default" with the default driver Creating hello-docker_backend_1 … done Creating hello-docker_frontend_1 … done # 可以看到服务已经运行了 $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 951784341a0d hello-docker_frontend "nginx -g 'daemon of…" 34 seconds ago Up 33 seconds 0.0.0.0:8080->80/tcp hello-docker_frontend_1 872c6a55316f hello-docker_backend "/usr/local/bin/back…" 35 seconds ago Up 33 seconds hello-docker_backend_1 # 通过context查看 $ docker ‐‐context default ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ed92bc991bad docker:19.03.3-dind "dockerd-entrypoint…." 28 minutes ago Up 28 minutes 0.0.0.0:2375->2375/tcp, 2376/tcp dind # 远程主机运行 $ docker-compose ‐‐context remote up -d /tmp/_MEIb4sAgX/paramiko/client.py:837: UserWarning: Unknown ssh-ed25519 host key for 10.0.0.52: b'047f5071513cab8c00d7944ef9d5d1fd' Creating network "hello-docker_default" with the default driver Creating hello-docker_backend_1 … done Creating hello-docker_frontend_1 … done # 切换当前上下文为default $ docker context use default default Current context is now "default" $ docker-compose up -d Creating network "hello-docker_default" with the default driver Creating hello-docker_backend_1 … done Creating hello-docker_frontend_1 … done $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 077b5e5b72e8 hello-docker_frontend "nginx -g 'daemon of…" About a minute ago Up about a minute 0.0.0.0:8080->80/tcp hello-docker_frontend_1 fc01878ad14e hello-docker_backend "/usr/local/bin/back…" About a minute ago Up about a minute hello-docker_backend_1 ed92bc991bad docker:19.03.3-dind "dockerd-entrypoint…." 34 minutes ago Up 34 minutes 0.0.0.0:2375->2375/tcp, 2376/tcp dind
5. 高级玩法
以投票应用程序为例,展示如何使用现有 Compose 文件创建 Docker 应用程序。
- docker app init
$ docker app init voting-app --compose-file docker-compose.yml Created "voting-app.dockerapp" $ tree . ├── docker-compose.yml ├── voting-app.dockerapp ├── docker-compose.yml ├── metadata.yml └── parameters.yml
- docker-compose.yml
version: "3.6" services: redis: image: redis:alpine ports: - "6379:6379" db: image: postgres:9.4 ports: - "5432:5432" vote: image: dockersamples/examplevotingapp_vote:before ports: - "${vote.port}:80" deploy: replicas: ${vote.replicas} result: image: dockersamples/examplevotingapp_result:before ports: - "${result.port}:80" worker: image: dockersamples/examplevotingapp_worker
- parameters.yml
vote: port: 5000 replicas: 2 result: port: 5001
6. 写在最后
期望越大,失望越大!
其实这篇博客,我修修改改了好几天了。一方面因为版本的更新,需要整理新版的功能特性以及对于的安装操作步骤;另一方面就是重新编写之前不再适配的内容,达到后续还可以按照该博客正常操作。博客更新完之后,我的内心其实是难过的。在新版本的 0.9.0 中,去除了我认为很重要的功能,就是更新配置文件,来重新生成各种环境的 docker-compose.yml 命令,哎,我感觉我要弃坑了。
下面是之前版本中,可以使用的命令功能,现在已经没有了,砍了 2/3 的子命令。我只能说,拜拜了,您嘞!