mirror of https://github.com/helm/helm
Add README.md to guestbook example. Remove local replicatedservice.py and reference the replicatedservice.py directly from the replicatedservice example from github in templates
parent
08c8e10c2d
commit
5bb61a4dbc
@ -0,0 +1,97 @@
|
|||||||
|
# Guestbook Example
|
||||||
|
|
||||||
|
Guestbook example shows how to bring up the
|
||||||
|
[Guestbook Example](https://github.com/kubernetes/kubernetes/tree/master/examples/guestbook)
|
||||||
|
from Kubernetes using Deployment Manager. It also shows you how to construct
|
||||||
|
and reuse parameterized templates.
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
It is assumed that you have bootstrapped the Deployment Manager on your cluster
|
||||||
|
by following the [README.md][https://github.com/kubernetes/deployment-manager/blob/master/README.md]
|
||||||
|
for bootstrapping the cluster.
|
||||||
|
|
||||||
|
## Deploying Guestbook
|
||||||
|
To deploy the Guestbook example, you run the following command.
|
||||||
|
|
||||||
|
```
|
||||||
|
client --name guestbook --service=http://localhost:8001/api/v1/proxy/namespaces/default/services/manager-service:manager examples/guestbook/guestbook.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Replicated Service
|
||||||
|
|
||||||
|
Typical pattern for deploying microservices in Kubernetes is to create both a
|
||||||
|
Replication Controller and a Service. We have created a parameterizable type
|
||||||
|
for that called [Replicated Service](https://github.com/kubernetes/deployment-manager/tree/master/examples/replicatedservice)
|
||||||
|
that we use throughout this example.
|
||||||
|
|
||||||
|
The Guestbook example consists of 2 services, a frontend and a Redis service.
|
||||||
|
Frontend is a replicated service with 3 replicas and is created like so:
|
||||||
|
```
|
||||||
|
- name: frontend
|
||||||
|
type: https://raw.githubusercontent.com/kubernetes/deployment-manager/master/examples/replicatedservice/replicatedservice.py
|
||||||
|
properties:
|
||||||
|
service_port: 80
|
||||||
|
container_port: 80
|
||||||
|
external_service: true
|
||||||
|
replicas: 3
|
||||||
|
image: gcr.io/google_containers/example-guestbook-php-redis:v3
|
||||||
|
```
|
||||||
|
|
||||||
|
Redis is a composite type and consists of two replicated services. A master with a single replica
|
||||||
|
and the slaves with 2 replicas. It's construced as follows:
|
||||||
|
```
|
||||||
|
{% set REDIS_PORT = 6379 %}
|
||||||
|
{% set WORKERS = properties['workers'] or 2 %}
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- name: redis-master
|
||||||
|
type: https://raw.githubusercontent.com/kubernetes/deployment-manager/master/examples/replicatedservice/replicatedservice.py
|
||||||
|
properties:
|
||||||
|
# This has to be overwritten since service names are hard coded in the code
|
||||||
|
service_name: redis-master
|
||||||
|
service_port: {{ REDIS_PORT }}
|
||||||
|
target_port: {{ REDIS_PORT }}
|
||||||
|
container_port: {{ REDIS_PORT }}
|
||||||
|
replicas: 1
|
||||||
|
container_name: master
|
||||||
|
image: redis
|
||||||
|
|
||||||
|
- name: redis-slave
|
||||||
|
type: https://raw.githubusercontent.com/kubernetes/deployment-manager/master/examples/replicatedservice/replicatedservice.py
|
||||||
|
properties:
|
||||||
|
# This has to be overwritten since service names are hard coded in the code
|
||||||
|
service_name: redis-slave
|
||||||
|
service_port: {{ REDIS_PORT }}
|
||||||
|
container_port: {{ REDIS_PORT }}
|
||||||
|
replicas: {{ WORKERS }}
|
||||||
|
container_name: worker
|
||||||
|
image: kubernetes/redis-slave:v2
|
||||||
|
# An example of how to specify env variables.
|
||||||
|
env:
|
||||||
|
- name: GET_HOSTS_FROM
|
||||||
|
value: env
|
||||||
|
- name: REDIS_MASTER_SERVICE_HOST
|
||||||
|
value: redis-master
|
||||||
|
```
|
||||||
|
|
||||||
|
### Displaying types
|
||||||
|
|
||||||
|
You can also (currently using curl, work in progress) see what types have been deployed to the cluster:
|
||||||
|
```
|
||||||
|
curl http://localhost:8001/api/v1/proxy/namespaces/default/services/manager-service:manager/types
|
||||||
|
["Service","ReplicationController","redis.jinja","https://raw.githubusercontent.com/kubernetes/deployment-manager/master/examples/replicatedservice/replicatedservice.py"]
|
||||||
|
```
|
||||||
|
|
||||||
|
This shows that there are 2 native types that we have deployed (Service and ReplicationController) and
|
||||||
|
2 composite types (redis.jinja and one imported from github (replicatedservice.py)).
|
||||||
|
|
||||||
|
|
||||||
|
You can also see where the types are being used by getting details on the particular type:
|
||||||
|
```
|
||||||
|
curl 'http://localhost:8001/api/v1/proxy/namespaces/default/services/manager-service:manager/types/redis.jinja/instances'
|
||||||
|
[{"name":"redis","type":"redis.jinja","deployment":"guestbook","manifest":"manifest-1446584669795839153","path":"$.resources[1]"}]
|
||||||
|
```
|
||||||
|
|
||||||
|
It lists which deployment and manifest as well as JSON path to the type.
|
||||||
|
|
@ -1,187 +0,0 @@
|
|||||||
"""Defines a ReplicatedService type by creating both a Service and an RC.
|
|
||||||
|
|
||||||
This module creates a typical abstraction for running a service in a
|
|
||||||
Kubernetes cluster, namely a replication controller and a service packaged
|
|
||||||
together into a single unit.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
SERVICE_TYPE_COLLECTION = 'Service'
|
|
||||||
RC_TYPE_COLLECTION = 'ReplicationController'
|
|
||||||
|
|
||||||
|
|
||||||
def GenerateConfig(context):
|
|
||||||
"""Generates a Replication Controller and a matching Service.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
context: Template context, which can contain the following properties:
|
|
||||||
container_name - Name to use for container. If omitted, name is
|
|
||||||
used.
|
|
||||||
namespace - Namespace to create the resources in. If omitted,
|
|
||||||
'default' is used.
|
|
||||||
service_name - Name to use for service. If omitted name-service is
|
|
||||||
used.
|
|
||||||
protocol - Protocol to use for the service
|
|
||||||
service_port - Port to use for the service
|
|
||||||
target_port - Target port for the service
|
|
||||||
container_port - Container port to use
|
|
||||||
replicas - Number of replicas to create in RC
|
|
||||||
image - Docker image to use for replicas. Required.
|
|
||||||
labels - labels to apply.
|
|
||||||
env - Environmental variables to apply (list of maps). Format
|
|
||||||
should be:
|
|
||||||
[{'name': ENV_VAR_NAME, 'value':'ENV_VALUE'},
|
|
||||||
{'name': ENV_VAR_NAME_2, 'value':'ENV_VALUE_2'}]
|
|
||||||
external_service - If set to true, enable external Load Balancer
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A Container Manifest as a YAML string.
|
|
||||||
"""
|
|
||||||
# YAML config that we're going to create for both RC & Service
|
|
||||||
config = {'resources': []}
|
|
||||||
|
|
||||||
name = context.env['name']
|
|
||||||
container_name = context.properties.get('container_name', name)
|
|
||||||
namespace = context.properties.get('namespace', 'default')
|
|
||||||
|
|
||||||
# Define things that the Service cares about
|
|
||||||
service_name = context.properties.get('service_name', name + '-service')
|
|
||||||
service_type = SERVICE_TYPE_COLLECTION
|
|
||||||
|
|
||||||
# Define things that the Replication Controller (rc) cares about
|
|
||||||
rc_name = name + '-rc'
|
|
||||||
rc_type = RC_TYPE_COLLECTION
|
|
||||||
|
|
||||||
service = {
|
|
||||||
'name': service_name,
|
|
||||||
'type': service_type,
|
|
||||||
'properties': {
|
|
||||||
'apiVersion': 'v1',
|
|
||||||
'kind': 'Service',
|
|
||||||
'namespace': namespace,
|
|
||||||
'metadata': {
|
|
||||||
'name': service_name,
|
|
||||||
'labels': GenerateLabels(context, service_name),
|
|
||||||
},
|
|
||||||
'spec': {
|
|
||||||
'ports': [GenerateServicePorts(context, container_name)],
|
|
||||||
'selector': GenerateLabels(context, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set_up_external_lb = context.properties.get('external_service', None)
|
|
||||||
if set_up_external_lb:
|
|
||||||
service['properties']['spec']['type'] = 'LoadBalancer'
|
|
||||||
config['resources'].append(service)
|
|
||||||
|
|
||||||
rc = {
|
|
||||||
'name': rc_name,
|
|
||||||
'type': rc_type,
|
|
||||||
'properties': {
|
|
||||||
'apiVersion': 'v1',
|
|
||||||
'kind': 'ReplicationController',
|
|
||||||
'namespace': namespace,
|
|
||||||
'metadata': {
|
|
||||||
'name': rc_name,
|
|
||||||
'labels': GenerateLabels(context, rc_name),
|
|
||||||
},
|
|
||||||
'spec': {
|
|
||||||
'replicas': context.properties['replicas'],
|
|
||||||
'selector': GenerateLabels(context, name),
|
|
||||||
'template': {
|
|
||||||
'metadata': {
|
|
||||||
'labels': GenerateLabels(context, name),
|
|
||||||
},
|
|
||||||
'spec': {
|
|
||||||
'containers': [
|
|
||||||
{
|
|
||||||
'env': GenerateEnv(context),
|
|
||||||
'name': container_name,
|
|
||||||
'image': context.properties['image'],
|
|
||||||
'ports': [
|
|
||||||
{
|
|
||||||
'name': container_name,
|
|
||||||
'containerPort': context.properties['container_port'],
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config['resources'].append(rc)
|
|
||||||
return yaml.dump(config)
|
|
||||||
|
|
||||||
|
|
||||||
# Generates labels either from the context.properties['labels'] or generates
|
|
||||||
# a default label 'name':name
|
|
||||||
def GenerateLabels(context, name):
|
|
||||||
"""Generates labels from context.properties['labels'] or creates default.
|
|
||||||
|
|
||||||
We make a deep copy of the context.properties['labels'] section to avoid
|
|
||||||
linking in the yaml document, which I believe reduces readability of the
|
|
||||||
expanded template. If no labels are given, generate a default 'name':name.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
context: Template context, which can contain the following properties:
|
|
||||||
labels - Labels to generate
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A dict containing labels in a name:value format
|
|
||||||
"""
|
|
||||||
tmp_labels = context.properties.get('labels', None)
|
|
||||||
ret_labels = {'name': name}
|
|
||||||
if isinstance(tmp_labels, dict):
|
|
||||||
for key, value in tmp_labels.iteritems():
|
|
||||||
ret_labels[key] = value
|
|
||||||
return ret_labels
|
|
||||||
|
|
||||||
|
|
||||||
def GenerateServicePorts(context, name):
|
|
||||||
"""Generates a ports section for a service.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
context: Template context, which can contain the following properties:
|
|
||||||
service_port - Port to use for the service
|
|
||||||
target_port - Target port for the service
|
|
||||||
protocol - Protocol to use.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A dict containing a port definition
|
|
||||||
"""
|
|
||||||
service_port = context.properties.get('service_port', None)
|
|
||||||
target_port = context.properties.get('target_port', None)
|
|
||||||
protocol = context.properties.get('protocol')
|
|
||||||
|
|
||||||
ports = {}
|
|
||||||
if name:
|
|
||||||
ports['name'] = name
|
|
||||||
if service_port:
|
|
||||||
ports['port'] = service_port
|
|
||||||
if target_port:
|
|
||||||
ports['targetPort'] = target_port
|
|
||||||
if protocol:
|
|
||||||
ports['protocol'] = protocol
|
|
||||||
|
|
||||||
return ports
|
|
||||||
|
|
||||||
def GenerateEnv(context):
|
|
||||||
"""Generates environmental variables for a pod.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
context: Template context, which can contain the following properties:
|
|
||||||
env - Environment variables to set.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A list containing env variables in dict format {name: 'name', value: 'value'}
|
|
||||||
"""
|
|
||||||
env = []
|
|
||||||
tmp_env = context.properties.get('env', [])
|
|
||||||
for entry in tmp_env:
|
|
||||||
if isinstance(entry, dict):
|
|
||||||
env.append({'name': entry.get('name'), 'value': entry.get('value')})
|
|
||||||
return env
|
|
Loading…
Reference in new issue