当前位置: 首页 > 工具软件 > Murano-Apps > 使用案例 >

Murano之:集成docker

海雪松
2023-12-01

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.0
Type: Library
FullName: io.murano.apps.docker.Interfaces
Name: Docker Interface Library
Description: |
 The library provides all necessary interface for Docker
 and Kubernetes applications
Author: '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.0
Version: 1.0.0
Name: Start docker service

Body: |
  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.murano

Name: DockerTomcat

Extends: DockerApplication

Properties:
  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的具体安装

 类似资料: