Arbeitsprotokollanwendung mit Netzwerklastenausgleich bereitstellen

In dieser Anleitung stellen Sie eine beispielhafte Arbeitsprotokollanwendung bereit, die Node.js als Front-End und MySQL im Back-End verwendet. Am Ende der Anleitung umfasst Ihre Bereitstellung folgende Ressourcen:

Bereitstellungsressourcen mit Netzwerklastenausgleich (zum Vergrößern klicken)

Wenn Sie den Deployment Manager noch nicht kennen, lesen Sie sich den Schnellstart oder die Schritt-für-Schritt-Anleitungen durch.

Vorbereitung

Ressourcenvorlagen erstellen

In diesem Beispiel wird eine Bereitstellung begonnen, die unterschiedliche Google Cloud Platform-Ressourcen enthält. Zuerst erstellen Sie Vorlagen, in denen diese Ressourcen getrennt definiert werden. Später nutzen Sie diese Vorlagen in Ihrer endgültigen Konfiguration. Ihre Bereitstellung enthält folgende Ressourcen:

  • Eine Compute Engine-Instanz, die eine MySQL-Datenbank für die Anwendung hostet.
  • Eine Instanzvorlage für Front-End-Instanzen, die ein Docker-Image für die Node.js-Anwendung verwendet.
  • Eine verwaltete Instanzgruppe, in der mit der Instanzvorlage zwei Front-End-Instanzen erstellt werden.
  • Autoscaling, das zusätzliche Front-End-Instanzen auf Basis von eingehendem Traffic startet oder stoppt.
  • Eine Systemdiagnose, die prüft, ob die Front-End-Instanzen verfügbar und funktionsfähig sind.
  • Ein Netzwerk-Lastenausgleichsmodul mit einer Weiterleitungsregel.
  • Ein Zielpool für die verwaltete Instanzgruppe.

Vorlage für das MySQL-Back-End erstellen

Das Back-End dieser Anwendung ist eine einzelne Compute Engine-Instanz, auf der ein MySQL Docker-Container ausgeführt wird. Die Vorlage container_vm.py definiert eine Compute Engine-Instanz, die Docker-Container ausführen kann. Um zu gewährleisten, dass die Vorlage die korrekte Struktur aufweist und alle erforderlichen Properties enthält, benötigen Sie außerdem eine Schemadatei.

Kopieren Sie die Vorlage unten oder laden Sie sie aus dem GitHub-Repository herunter:

# Copyright 2016 Google Inc. All rights reserved.
#
# 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.

"""Creates a Container VM with the provided Container manifest."""

from container_helper import GenerateManifest

COMPUTE_URL_BASE = 'https://www.googleapis.com/compute/v1/'

def GlobalComputeUrl(project, collection, name):
  return ''.join([COMPUTE_URL_BASE, 'projects/', project,
                  '/global/', collection, '/', name])

def ZonalComputeUrl(project, zone, collection, name):
  return ''.join([COMPUTE_URL_BASE, 'projects/', project,
                  '/zones/', zone, '/', collection, '/', name])

def GenerateConfig(context):
  """Generate configuration."""

  base_name = context.env['name']

  # Properties for the container-based instance.
  instance = {
      'zone': context.properties['zone'],
      'machineType': ZonalComputeUrl(context.env['project'],
                                     context.properties['zone'],
                                     'machineTypes',
                                     'f1-micro'),
      'metadata': {
          'items': [{
              'key': 'google-container-manifest',
              'value': GenerateManifest(context)
              }]
          },
      'disks': [{
          'deviceName': 'boot',
          'type': 'PERSISTENT',
          'autoDelete': True,
          'boot': True,
          'initializeParams': {
              'diskName': base_name + '-disk',
              'sourceImage': GlobalComputeUrl('google-containers',
                                              'images',
                                              context.properties[
                                                  'containerImage'])
              },
          }],
      'networkInterfaces': [{
          'accessConfigs': [{
              'name': 'external-nat',
              'type': 'ONE_TO_ONE_NAT'
              }],
          'network': GlobalComputeUrl(context.env['project'],
                                      'networks',
                                      'default')
          }]
      }

  # Resources to return.
  resources = {
      'resources': [{
          'name': base_name,
          'type': 'compute.v1.instance',
          'properties': instance
          }]
      }

  return resources

Schemadatei für die Vorlage herunterladen

Die Vorlage enthält einige nicht definierte Properties, zum Beispiel containerImage, die in nachfolgenden Vorlagen definiert werden.

Wenn Sie Container-Images auf Compute Engine-Instanzen verwenden, müssen Sie außerdem eine Manifestdatei zur Verfügung stellen. In dieser wird angegeben, welches Container-Image zu verwenden ist. Erstellen Sie eine Hilfsmethode namens container_helper.py, um das Containermanifest dynamisch zu definieren:

# Copyright 2016 Google Inc. All rights reserved.
#
# 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.

"""Helper methods for working with containers in config."""

import yaml

def GenerateManifest(context):
  """Generates a Container Manifest given a Template context.

  Args:
    context: Template context, which must contain dockerImage and port
        properties, and an optional dockerEnv property.

  Returns:
    A Container Manifest as a YAML string.
  """
  env_list = []
  if 'dockerEnv' in context.properties:
    for key, value in context.properties['dockerEnv'].iteritems():
      env_list.append({'name': key, 'value': str(value)})

  manifest = {
      'apiVersion': 'v1',
      'kind': 'Pod',
      'metadata': {
          'name': context.env['name']
          },
      'spec': {
          'containers': [{
              'name': context.env['name'],
              'image': context.properties['dockerImage'],
              'ports': [{
                  'hostPort': context.properties['port'],
                  'containerPort': context.properties['port']
                  }],
              }]
          }
      }

  if env_list:
    manifest['spec']['containers'][0]['env'] = env_list

  return yaml.dump(manifest, default_flow_style=False)

Vorlage für das Node.js-Front-End erstellen

Das Front-End der Anwendung führt Node.js aus und ermöglicht Nutzern, Nachrichten auf der Webseite zu posten. Die Ausführung des Front-Ends erfolgt auf einer Gruppe von virtuellen Maschinen, die durch Autoscaling und ein Lastenausgleichsmodul unterstützt werden. Gehen Sie beim Erstellen von Front-End-Vorlagen folgendermaßen vor:

  1. Erstellen Sie eine Instanzvorlagenressource.

    Sie benötigen eine Instanzvorlage, um eine verwaltete Instanzgruppe zu erstellen. Hierbei handelt es sich um eine Gruppe identischer VM-Instanzen, die Sie als eine Entität steuern.

    Erstellen Sie eine Datei namens container_instance_template.py und laden Sie das Schema für die Vorlage herunter:

    # Copyright 2016 Google Inc. All rights reserved.
    #
    # 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.
    
    """Creates a Container VM with the provided Container manifest."""
    
    from container_helper import GenerateManifest
    
    def GenerateConfig(context):
      """Generates configuration."""
    
      image = ''.join(['https://www.googleapis.com/compute/v1/',
                       'projects/google-containers/global/images/',
                       context.properties['containerImage']])
      default_network = ''.join(['https://www.googleapis.com/compute/v1/projects/',
                                 context.env['project'],
                                 '/global/networks/default'])
    
      instance_template = {
          'name': context.env['name'] + '-it',
          'type': 'compute.v1.instanceTemplate',
          'properties': {
              'properties': {
                  'metadata': {
                      'items': [{
                          'key': 'google-container-manifest',
                          'value': GenerateManifest(context)
                          }]
                      },
                  'machineType': 'f1-micro',
                  'disks': [{
                      'deviceName': 'boot',
                      'boot': True,
                      'autoDelete': True,
                      'mode': 'READ_WRITE',
                      'type': 'PERSISTENT',
                      'initializeParams': {'sourceImage': image}
                      }],
                  'networkInterfaces': [{
                      'accessConfigs': [{
                          'name': 'external-nat',
                          'type': 'ONE_TO_ONE_NAT'
                          }],
                      'network': default_network
                      }]
                  }
              }
          }
    
      outputs = [{'name': 'instanceTemplateSelfLink',
                  'value': '$(ref.' + instance_template['name'] + '.selfLink)'}]
    
      return {'resources': [instance_template], 'outputs': outputs}
    

    Schemadatei für die Vorlage herunterladen

  2. Erstellen Sie Autoscaling, eine verwaltete Instanzgruppe und Lastenausgleich.

    Erstellen Sie dann eine weitere Vorlage, die die Vorlage container_instance_template.py verwendet und die restlichen Front-End-Ressourcen erstellt, einschließlich Autoscaling, Lastenausgleichsmodul und einer verwalteten Instanzgruppe.

Diese Vorlage enthält folgende Ressourcen:

  1. Eine Instanzvorlage, die die Vorlage container_instance_template.py verwendet.

  2. Eine verwaltete Instanzgruppe, die die Instanzvorlage verwendet, und Autoscaling, das die verwaltete Instanzgruppe referenziert. Mithilfe von Referenzen wird gewährleistet, dass der Deployment Manager die Ressourcen in einer bestimmten Reihenfolge erstellt. In diesem Fall wird die verwaltete Instanzgruppe vor dem Autoscaling erstellt.

  3. Ein Netzwerk-Lastenausgleichsmodul, das folgende Ressourcen enthält:

    • Eine Weiterleitungsregel mit einer einzelnen externen IP-Adresse, die im Internet freigegeben ist.
    • Einen Zielpool, der die verwaltete Instanzgruppe enthält, die Sie erstellt haben.
    • Eine Systemdiagnose zur Verbindung mit dem Zielpool.

Erstellen Sie eine Datei namens frontend.py und laden Sie das Schema für die Vorlage herunter:

# Copyright 2016 Google Inc. All rights reserved.
#
# 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.

"""Creates autoscaled, network LB IGM running specified docker image."""

def GenerateConfig(context):
  """Generate YAML resource configuration."""

  # Pull the region out of the zone
  region = context.properties['zone'][:context.properties['zone'].rfind('-')]
  name = context.env['name']

  resources = [{
      'name': name,
      'type': 'container_instance_template.py',
      'properties': {
          'port': context.properties['port'],
          'dockerEnv': context.properties['dockerEnv'],
          'dockerImage': context.properties['dockerImage'],
          'containerImage': context.properties['containerImage']
      }
  }, {
      'name': name + '-igm',
      'type': 'compute.v1.instanceGroupManager',
      'properties': {
          'zone': context.properties['zone'],
          'targetSize': context.properties['size'],
          'targetPools': ['$(ref.' + name + '-tp.selfLink)'],
          'baseInstanceName': name + '-instance',
          'instanceTemplate': '$(ref.' + name + '-it.selfLink)'
      }
  }, {
      'name': name + '-as',
      'type': 'compute.v1.autoscaler',
      'properties': {
          'zone': context.properties['zone'],
          'target': '$(ref.' + name + '-igm.selfLink)',
          'autoscalingPolicy': {
              'maxNumReplicas': context.properties['maxSize']
          }
      }
  }, {
      'name': name + '-hc',
      'type': 'compute.v1.httpHealthCheck',
      'properties': {
          'port': context.properties['port'],
          'requestPath': '/_ah/health'
      }
  }, {
      'name': name + '-tp',
      'type': 'compute.v1.targetPool',
      'properties': {
          'region': region,
          'healthChecks': ['$(ref.' + name + '-hc.selfLink)']
      }
  }, {
      'name': name + '-lb',
      'type': 'compute.v1.forwardingRule',
      'properties': {
          'region': region,
          'portRange': context.properties['port'],
          'target': '$(ref.' + name + '-tp.selfLink)'
      }
  }]
  return {'resources': resources}

Schemadatei für die Vorlage herunterladen

Gemeinsame Vorlage erstellen

Erstellen Sie schließlich eine Vorlage zur Kombination der Back-End- und Front-End-Vorlagen. Erstellen Sie eine Datei namens nodejs.py mit folgendem Inhalt:

# Copyright 2016 Google Inc. All rights reserved.
#
# 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.

"""Create nodejs template with the back-end and front-end templates."""

def GenerateConfig(context):
  """Generate configuration."""

  backend = context.env['deployment'] + '-backend'
  frontend = context.env['deployment'] + '-frontend'
  firewall = context.env['deployment'] + '-application-fw'
  application_port = 8080
  mysql_port = 8080
  resources = [{
      'name': backend,
      'type': 'container_vm.py',
      'properties': {
          'zone': context.properties['zone'],
          'dockerImage': 'gcr.io/deployment-manager-examples/mysql',
          'containerImage': 'container-vm-v20160217',
          'port': mysql_port
      }
  }, {
      'name': frontend,
      'type': 'frontend.py',
      'properties': {
          'zone': context.properties['zone'],
          'dockerImage': 'gcr.io/deployment-manager-examples/nodejsservice',
          'port': application_port,
          # Define the variables that are exposed to container as env variables.
          'dockerEnv': {
              'SEVEN_SERVICE_MYSQL_PORT': mysql_port,
              'SEVEN_SERVICE_PROXY_HOST': '$(ref.' + backend
                                          + '.networkInterfaces[0].networkIP)'
          },
          # If left out will default to 1
          'size': 2,
          # If left out will default to 1
          'maxSize': 20
      }
  }, {
      'name': firewall,
      'type': 'compute.v1.firewall',
      'properties': {
          'allowed': [{
              'IPProtocol': 'TCP',
              'ports': [application_port]
          }],
          'sourceRanges': ['0.0.0.0/0']
      }
  }]
  return {'resources': resources}

Schemadatei für die Vorlage herunterladen

Das Front-End Ihrer Anwendung heißt env["deployment"]-frontend und Ihr Back-End ist ähnlich benannt. Wenn Sie die Anwendung bereitstellen, ersetzt der Deployment Manager automatisch env["deployment"] durch den Bereitstellungsnamen.

Konfiguration erstellen

Nachdem Sie mit allen Vorlagen fertig sind, können Sie eine Konfiguration erstellen, um Ihre Ressourcen bereitzustellen. Erstellen Sie eine Konfigurationsdatei mit dem Namen nodejs.yaml und folgendem Inhalt:

# Copyright 2016 Google Inc. All rights reserved.
#
# 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.

# Launches an autoscaled, load-balanced frontend running nodejs for serving
# traffic. Also launches a single MySQL container instance, wires the two
# together using references, and passes them as env variables to the underlying
# frontend Docker containers.
imports:
- path: nodejs.py

resources:
- name: nodejs
  type: nodejs.py
  properties:
    zone: ZONE_TO_RUN

Ersetzen Sie ZONE_TO_RUN durch die Zone, in der sich Ihre Ressourcen befinden sollen, beispielsweise us-central1-a.

Ressourcen bereitstellen

Stellen Sie jetzt Ihre Ressourcen bereit. Führen Sie mit dem Befehlszeilentool gcloud folgenden Befehl aus:

gcloud deployment-manager deployments create advanced-configuration --config nodejs.yaml

Wenn die Bereitstellung abgeschlossen ist, zeigt der Deployment Manager eine Zusammenfassung der erstellten Ressourcen an, die etwa wie folgt aussieht:

Waiting for create operation-1468522101491-5379cf2344539-5961abe8-a500190c...done.
Create operation operation-1468522101491-5379cf2344539-5961abe8-a500190c completed successfully.
NAME                                   TYPE                             STATE      ERRORS
advanced-configuration-application-fw  compute.v1.firewall              COMPLETED  []
advanced-configuration-backend         compute.v1.instance              COMPLETED  []
advanced-configuration-frontend-as     compute.v1.autoscaler            COMPLETED  []
advanced-configuration-frontend-hc     compute.v1.httpHealthCheck       COMPLETED  []
advanced-configuration-frontend-igm    compute.v1.instanceGroupManager  COMPLETED  []
advanced-configuration-frontend-it     compute.v1.instanceTemplate      COMPLETED  []
advanced-configuration-frontend-lb     compute.v1.forwardingRule        COMPLETED  []
advanced-configuration-frontend-tp     compute.v1.targetPool            COMPLETED  []

Anwendung testen

Um Ihre Anwendung zu testen, ermitteln Sie zuerst die externe IP-Adresse, die den Traffic weiterleitet. Fragen Sie dazu folgende Weiterleitungsregel ab:

$ gcloud compute forwarding-rules describe advanced-configuration-frontend-lb --region us-central1
IPAddress: 104.154.81.44
IPProtocol: TCP
creationTimestamp: '2016-07-14T11:48:37.228-07:00'
description: ''
id: '9033201246750269546'
kind: compute#forwardingRule
name: advanced-configuration-frontend-lb
portRange: 8080-8080
region: https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1
selfLink: https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1/forwardingRules/advanced-configuration-frontend-lb
target: https://www.googleapis.com/compute/v1/projects/myproject/regions/us-central1/targetPools/advanced-configuration-frontend-tp

In diesem Fall ist die externe IP 104.154.81.44.

Rufen Sie dann in einem Browser die externe IP-Adresse mit Port 8080 auf. Wenn Ihre externe IP-Adresse beispielsweise 104.154.81.44 lautet, ist die URL:

http://104.154.81.44:8080

Es sollte eine leere Seite angezeigt werden. Posten Sie dann eine Nachricht auf der Seite. Wechseln Sie zur folgenden URL:

http://104.154.81.44:8080?msg=hellothere!

Es wird bestätigt, dass Ihre Nachricht hinzugefügt wurde. Navigieren Sie zurück zur Haupt-URL und die Seite sollte jetzt folgende Meldung enthalten:

hellothere!

Sie haben jetzt eine bereitgestellte Anwendung, die an sie gesendete Nachrichten protokollieren kann.

Weitere Informationen

Wenn Sie mit diesem Beispiel fertig sind, haben Sie folgende Möglichkeiten:

Hat Ihnen diese Seite weitergeholfen? Teilen Sie uns Ihr Feedback mit:

Feedback geben zu...

Cloud Deployment Manager-Dokumentation