Murano之:集成docker

来源:互联网 发布:青岛方特梦幻王国知乎 编辑:程序博客网 时间:2024/04/30 11:05

murano是如何集成docker?提供了怎样的接口以辅助用户快捷的编写package呢?这个得利于murano自身的架构,murano的package提供了自定义lib的功能,即根据自己的需要,根据murano package的定义规则,自己拓展一个即可。关于murano package的解析请移步murano实践之package分析

DockerInterfacesLibrary

DockerInterfacesLibrary 中提供了对于一个已正确安装docker环境的虚拟机操作docker的接口,首先看下package中的manifest.yaml
见:murano-apps/manifest.yaml

Format: 1.0Type: LibraryFullName: io.murano.apps.docker.InterfacesName: Docker Interface LibraryDescription: | The library provides all necessary interface for Docker and Kubernetes applicationsAuthor: 'Mirantis, Inc'Tags: [Docker, Kubernetes]Classes: io.murano.apps.docker.DockerApplication: DockerApplication.yaml io.murano.apps.docker.DockerContainer: DockerContainer.yaml io.murano.apps.docker.DockerContainerHost: DockerContainerHost.yaml io.murano.apps.docker.DockerHelpers: DockerHelpers.yaml io.murano.apps.docker.DockerHostVolume: DockerHostVolume.yaml io.murano.apps.docker.DockerTempVolume: DockerTempVolume.yaml io.murano.apps.docker.DockerVolume: DockerVolume.yaml io.murano.apps.docker.ApplicationPort: ApplicationPort.yaml

重点在Classes中,目前这里面主要封装了

  • DockerApplication
  • DockerContainer
  • DockerContainerHost
  • DockerHelpers
  • DockerHostVolume
  • DockerTempVolume
  • DockerVolume
  • ApplicationPort

这8个docker相关的接口,我们这里以DockerApplication为例做一个分析,在Classes文件包中找到DockerApplication.yaml
提供了deploydestroygetConnectionTo等方法。以deploy为例,显示了虚拟机使用docker安装application的步骤

  deploy:    Body:      - $.host.deploy()      - $container: $.getContainer()      - $repr: $._getContainerRepresentation($container)      - If: $.getAttr(container, null) != $repr        Then:        - $.onInstallationStart()        - Try:          - $.applicationEndpoints: $.host.hostContainer($container)          - $.setAttr(container, $repr)          Catch:          - As: e            Do:            - $formatString: 'Error: {0}'            - $._environment.reporter.report_error($, $formatString.format($e.message))            - Rethrow:          Else:          - $.onInstallationFinish()

首先$.host.deploy(),这个hostDockerStandaloneHost 详见DockerStandaloneHost,具有方法deploy,此处调用的也是deploy方法DockerStandaloneHostdeploy方法如下:

  deploy:    Body:      - If: not $.getAttr(deployed, false)        Then:          - $._environment.reporter.report($this, 'Create VM for Docker Server')          - $.instance.deploy()          - $resources: new(sys:Resources)          - $template: $resources.yaml('StartDocker.template')          - $.instance.agent.call($template, $resources)          - If: $.dockerRegistry != null and $.dockerRegistry != ''            Then:              - $._environment.reporter.report($this, 'Configuring Docker registry')              - $template: $resources.yaml('SetupDockerRegistry.template').bind(dict(                    dockerRegistry => $.dockerRegistry                  ))              - $.instance.agent.call($template, $resources)          - $._environment.reporter.report($this, 'Docker Server is up and running')          - $.setAttr(deployed, true)

- $.instance.deploy()- $resources: new(sys:Resources)- $template: $resources.yaml('StartDocker.template')- $.instance.agent.call($template, $resources)

这四步看出,需要拿到StartDocker.template 交给LinuxMuranoInstanceStartDocker.template中的内容如下:
startDocker.template

FormatVersion: 2.0.0Version: 1.0.0Name: Start docker serviceBody: |  startDocker()Scripts:  startDocker:    Type: Application    Version: 1.0.0    EntryPoint: startDocker.sh    Options:      captureStdout: false      captureStderr: false      verifyExitcode: false

这个template的EntryPoint是startDocker.sh,内容:

#!/bin/bash#  Licensed under the Apache License, Version 2.0 (the "License"); you may#  not use this file except in compliance with the License. You may obtain#  a copy of the License at##       http://www.apache.org/licenses/LICENSE-2.0##  Unless required by applicable law or agreed to in writing, software#  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT#  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the#  License for the specific language governing permissions and limitations#  under the License.service docker start

一句话,启动docker服务,所以$.host.deploy() 其实就是用了启动虚拟机上的docker服务;根据上面的方法,

- $container: $.getContainer()- $repr: $._getContainerRepresentation($container)

这两步获取container的基础信息
再看- $.host.hostContainer(container)
对应的方法如下:

  hostContainer:    Arguments:      - container:          Contract: $.class(DockerContainer).notNull()    Body:      - $.deploy()      - $.deleteContainer($container.name)      - $portBindings: {}      - $newEndpoints: []      - $._pullImage(image => $container.image)      - For: applicationPort        In: $container.ports        Do:          - If: $applicationPort.scope != host            Then:              - $hostPort: $._acquirePort($applicationPort, $container.name)              - $containerPort: $._getPortSpec($applicationPort)              - $portBindings[$hostPort]: $containerPort              - If: $applicationPort.scope = public                Then:                  - $rule:                      - ToPort: $hostPort                        FromPort: $hostPort                        IpProtocol: toLower($applicationPort.protocol)                        External: true                  - $._environment.securityGroupManager.addGroupIngress($rule)              - $record:                  port: $hostPort                  address: $.instance.ipAddresses[0]                  scope: cloud                  containerPort: $applicationPort.port                  portScope: $applicationPort.scope                  protocol: $applicationPort.protocol                  applicationName: $container.name              - $newEndpoints: $newEndpoints + list($record)              - If: $applicationPort.scope = public and $.instance.floatingIpAddress != null                Then:                  - $record.address: $.instance.floatingIpAddress                  - $record.scope: public                  - $newEndpoints: $newEndpoints + list($record)      - $volumeMap: {}      - For: path        In: $container.volumes        Do:          - $volume: $container.volumes.get($path)          - If: $volume.getType() = HostDir            Then:              - $hostDir: $volume.getParameters()              - $volumeMap[$hostDir]: $path      - $._environment.reporter.report($this, 'Adding Docker Application')      - $resources: new(sys:Resources)      - $template: $resources.yaml('RunContainer.template').bind(dict(            appName => $container.name,            image => $container.image,            env => $container.env,            portMap => $portBindings,            volumeMap => $volumeMap,            commands => $container.commands          ))      - $._removeApplicationEndpoints($container.name)      - $privateIp: $.instance.agent.call($template, $resources)      - $record:          port: $applicationPort.port          address: $privateIp          scope: host          containerPort: $applicationPort.port          portScope: $applicationPort.scope          protocol: $applicationPort.protocol          applicationName: $container.name      - $newEndpoints: $newEndpoints + list($record)      - $._environment.stack.push()      - If: not $container.name in $.containers        Then:          - $.containers: $.containers + list($container.name)      - $.applicationEndpoints: $.applicationEndpoints + $newEndpoints      - Return: $.getEndpoints($container.name)

前面几步,判断该container是否存在,如果存在,删除- $._pullImage(image => $container.image) 这一步获取$container.image。中间到- $volumeMap: {} 之前的这一段就是为了组装portBindings和newEndpoints,接着组装volumeMap,完事儿之后呢获取RunContainer.template- $privateIp: $.instance.agent.call($template, $resources) 到这一步了自然就是告诉虚拟机,你该调用RunContainer.template 工作啦,RunContainer.template 中其实归根到底就是一段拼装好的执行docker run 命令的脚本。

从上面的分析可以看出来,DockerInterfacesLibrary 事实上是依赖DockerStandaloneHostLinuxMuranoInstance 的这两个对象事实需要创建虚拟机的镜像中包含了murano-agent服务和docker服务的,DockerStandaloneHost 中封装了StandaloneHost对docker的一些操作,如docker runservice docker start 等,LinuxMuranoInstance 中封装的是获取组装好的模版执行等功能。

以tomcat为例分析

DockerTomcat

Namespaces:  =: io.murano.apps.docker  std: io.muranoName: DockerTomcatExtends: DockerApplicationProperties:  name:    Contract: $.string().notNull()  publish:    Contract: $.bool().notNull()    Default: true  password:    Contract: $.string().notNull()Methods:  initialize:    Body:      - $._environment: $.find(std:Environment).require()      - $._scope: switch($.publish, $ => public, not $ => internal)  getContainer:    Body:      Return:        name: $.name        image: 'tutum/tomcat'        env:          TOMCAT_PASS: $.password        ports:          - port: 8080            scope: $._scope  onInstallationStart:    Body:      - $._environment.reporter.report($this, 'Installing Tomcat')  onInstallationFinish:    Body:      - If: $.publish        Then:          - $endpoints: $.applicationEndpoints.where($.scope = $this._scope).              select(format('http://{0}:{1}', $.address, $.port))          - $._environment.reporter.report($this, 'Tomcat {0} is available at {1}'.format($.name, join(', ', $endpoints)))        Else:          - $._environment.reporter.report($this, 'Tomcat {0} has deployed but is not accessible from outside'.format($.name))

Extends: DockerApplication 直接表明,继承了DockerApplication,也就是上面分析的DockerApplication实例,此处只需要实现getContaineronInstallationFinish 方法即可,deploy 会自动从DockerApplication继承,deploy 方法完成tomcat的具体安装

0 0