Skip to content

Commit

Permalink
feat(container): allow configuring # of replicas for container services
Browse files Browse the repository at this point in the history
Also added `project-variables` project to showcase the usage.
  • Loading branch information
edvald committed Jun 23, 2019
1 parent f062615 commit ad7c973
Show file tree
Hide file tree
Showing 25 changed files with 313 additions and 20 deletions.
16 changes: 14 additions & 2 deletions docs/reference/module-types/container.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ The names of any services that this service depends on at runtime, and the names

[services](#services) > annotations

Annotations to attach to the service (Note: May not be applicable to all providers)
Annotations to attach to the service (Note: May not be applicable to all providers).

| Type | Required |
| ---- | -------- |
Expand Down Expand Up @@ -351,7 +351,7 @@ services:

[services](#services) > daemon

Whether to run the service as a daemon (to ensure only one runs per node).
Whether to run the service as a daemon (to ensure exactly one instance runs per node). May not be supported by all providers.

| Type | Required |
| ---- | -------- |
Expand Down Expand Up @@ -652,6 +652,17 @@ Set this to expose the service on the specified port on the host node (may not b
| ---- | -------- |
| `number` | No

### `services[].replicas`

[services](#services) > replicas

The number of instances of the service to deploy.
Note: This setting may be overridden or ignored in some cases. For example, when running with `daemon: true`, with hot-reloading enabled, or if the provider doesn't support multiple replicas.

| Type | Required |
| ---- | -------- |
| `number` | No

### `services[].volumes[]`

[services](#services) > volumes
Expand Down Expand Up @@ -929,6 +940,7 @@ services:
servicePort: <containerPort>
hostPort:
nodePort:
replicas: 1
volumes:
- name:
containerPath:
Expand Down
16 changes: 14 additions & 2 deletions docs/reference/module-types/maven-container.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ The names of any services that this service depends on at runtime, and the names

[services](#services) > annotations

Annotations to attach to the service (Note: May not be applicable to all providers)
Annotations to attach to the service (Note: May not be applicable to all providers).

| Type | Required |
| ---- | -------- |
Expand Down Expand Up @@ -356,7 +356,7 @@ services:

[services](#services) > daemon

Whether to run the service as a daemon (to ensure only one runs per node).
Whether to run the service as a daemon (to ensure exactly one instance runs per node). May not be supported by all providers.

| Type | Required |
| ---- | -------- |
Expand Down Expand Up @@ -657,6 +657,17 @@ Set this to expose the service on the specified port on the host node (may not b
| ---- | -------- |
| `number` | No

### `services[].replicas`

[services](#services) > replicas

The number of instances of the service to deploy.
Note: This setting may be overridden or ignored in some cases. For example, when running with `daemon: true`, with hot-reloading enabled, or if the provider doesn't support multiple replicas.

| Type | Required |
| ---- | -------- |
| `number` | No

### `services[].volumes[]`

[services](#services) > volumes
Expand Down Expand Up @@ -964,6 +975,7 @@ services:
servicePort: <containerPort>
hostPort:
nodePort:
replicas: 1
volumes:
- name:
containerPath:
Expand Down
5 changes: 2 additions & 3 deletions docs/using-garden/configuration-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -399,15 +399,14 @@ key:
kind: Project
...
variables:
global-memory-limit: 100
default-replicas: 3
---
kind: Module
...
services:
- name: my-service
...
limits:
memory: ${var.global-memory-limit} # <- resolves to a number, as opposed to the string "100"
replicas: ${var.default-replicas} # <- resolves to a number, as opposed to the string "3"
```

If, however, the template string is not the whole string being interpolated, but a component of it, the value is
Expand Down
3 changes: 3 additions & 0 deletions examples/demo-project/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Demo project

A very basic demo project for Garden. Used in the [Quick Start guide](https://docs.garden.io/basics/quick-start).
10 changes: 10 additions & 0 deletions examples/project-variables/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Project variables

This variant of the basic [demo project](../demo-project/README.md) demonstrate the use of project variables.

In this example, we set a project variable in the [project config](./garden.yml) called `service-replicas` and
reference that variable in the module configs, in this case to set the number of replicas per service.

We also show how you can alternate these variables by the environment you're running, by overriding the default value
in the `local` environment. In this case, we only want _one_ replica of each service while developing locally, but
default to three when deploying remotely.
4 changes: 4 additions & 0 deletions examples/project-variables/backend/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
Dockerfile
garden.yml
app.yaml
27 changes: 27 additions & 0 deletions examples/project-variables/backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so

# Folders
_obj
_test

# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out

*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*

_testmain.go

*.exe
*.test
*.prof

.vscode/settings.json
webserver/*server*
14 changes: 14 additions & 0 deletions examples/project-variables/backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM golang:1.8.3-alpine
MAINTAINER Aurelien PERRIER <[email protected]>

ENV webserver_path /go/src/github.com/perriea/webserver/
ENV PATH $PATH:$webserver_path

WORKDIR $webserver_path
COPY webserver/ .

RUN go build .

ENTRYPOINT ./webserver

EXPOSE 8080
14 changes: 14 additions & 0 deletions examples/project-variables/backend/garden.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
kind: Module
name: backend
description: Backend service container
type: container
services:
- name: backend
replicas: ${var.service-replicas} # <- Refers to the variable set in the project config
ports:
- name: http
containerPort: 8080
servicePort: 80
ingresses:
- path: /hello-backend
port: http
17 changes: 17 additions & 0 deletions examples/project-variables/backend/webserver/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package main

import (
"fmt"
"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello from Go!")
}

func main() {
http.HandleFunc("/hello-backend", handler)
fmt.Println("Server running...")

http.ListenAndServe(":8080", nil)
}
4 changes: 4 additions & 0 deletions examples/project-variables/frontend/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
Dockerfile
garden.yml
app.yaml
12 changes: 12 additions & 0 deletions examples/project-variables/frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM node:9-alpine

ENV PORT=8080
EXPOSE ${PORT}
WORKDIR /app

ADD package.json /app
RUN npm install

ADD . /app

CMD ["npm", "start"]
28 changes: 28 additions & 0 deletions examples/project-variables/frontend/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const express = require('express');
const request = require('request-promise')
const app = express();

const backendServiceEndpoint = `http://backend/hello-backend`
// const backendServiceEndpoint = `http://demo-project.local.app.garden/hello-backend`

app.get('/hello-frontend', (req, res) => res.send('Hello from the frontend!'));

app.get('/call-backend', (req, res) => {
// Query the backend and return the response
request.get(backendServiceEndpoint)
.then(message => {
message = `Backend says: '${message}'`
res.json({
message,
})
})
.catch(err => {
res.statusCode = 500
res.json({
error: err,
message: "Unable to reach service at " + backendServiceEndpoint,
})
});
});

module.exports = { app }
28 changes: 28 additions & 0 deletions examples/project-variables/frontend/garden.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
kind: Module
name: frontend
description: Frontend service container
type: container
services:
- name: frontend
replicas: ${var.service-replicas} # <- Refers to the variable set in the project config
ports:
- name: http
containerPort: 8080
healthCheck:
httpGet:
path: /hello-frontend
port: http
ingresses:
- path: /hello-frontend
port: http
- path: /call-backend
port: http
dependencies:
- backend
tests:
- name: unit
args: [npm, test]
- name: integ
args: [npm, run, integ]
dependencies:
- backend
3 changes: 3 additions & 0 deletions examples/project-variables/frontend/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const { app } = require('./app');

app.listen(process.env.PORT, '0.0.0.0', () => console.log('Frontend service started'));
22 changes: 22 additions & 0 deletions examples/project-variables/frontend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "frontend",
"version": "1.0.0",
"description": "Simple Node.js docker service",
"main": "main.js",
"scripts": {
"start": "node main.js",
"test": "echo OK",
"integ": "node_modules/mocha/bin/mocha test/integ.js"
},
"author": "garden.io <[email protected]>",
"license": "ISC",
"dependencies": {
"express": "^4.16.2",
"request": "^2.83.0",
"request-promise": "^4.2.2"
},
"devDependencies": {
"mocha": "^5.1.1",
"supertest": "^3.0.0"
}
}
17 changes: 17 additions & 0 deletions examples/project-variables/frontend/test/integ.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const supertest = require("supertest")
const { app } = require("../app")

describe('GET /call-backend', () => {
const agent = supertest.agent(app)

it('should respond with a message from the backend service', (done) => {
agent
.get("/call-backend")
.expect(200, { message: "Backend says: 'Hello from Go!'" })
.end((err) => {
if (err) return done(err)
done()
})
})
})

19 changes: 19 additions & 0 deletions examples/project-variables/garden.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
kind: Project
name: project-variables
variables:
# This variable is referenced in the module configs, and overridden in the local project below
service-replicas: 3
environments:
- name: local
providers:
- name: local-kubernetes
variables:
# We only want one replica of each service when developing locally
service-replicas: 1
- name: testing
providers:
- name: kubernetes
context: gke_garden-dev-200012_europe-west1-b_garden-dev-1
namespace: ${project.name}-testing-${local.env.CIRCLE_BUILD_NUM || "default"}
defaultHostname: ${project.name}-testing.dev-1.sys.garden
buildMode: cluster-docker
18 changes: 16 additions & 2 deletions garden-service/src/plugins/container/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export interface ContainerServiceSpec extends CommonServiceSpec {
hotReloadArgs?: string[],
limits: ServiceLimitSpec,
ports: ServicePortSpec[],
replicas: number,
volumes: ServiceVolumeSpec[],
}

Expand Down Expand Up @@ -224,7 +225,7 @@ const volumeSchema = Joi.object()
const serviceSchema = baseServiceSpecSchema
.keys({
annotations: annotationsSchema
.description("Annotations to attach to the service (Note: May not be applicable to all providers)"),
.description("Annotations to attach to the service (Note: May not be applicable to all providers)."),
command: Joi.array().items(Joi.string())
.description("The command/entrypoint to run the container with when starting the service.")
.example([commandExample, {}]),
Expand All @@ -233,7 +234,10 @@ const serviceSchema = baseServiceSpecSchema
.example([["npm", "start"], {}]),
daemon: Joi.boolean()
.default(false)
.description("Whether to run the service as a daemon (to ensure only one runs per node)."),
.description(deline`
Whether to run the service as a daemon (to ensure exactly one instance runs per node).
May not be supported by all providers.
`),
ingresses: joiArray(ingressSchema)
.description("List of ingress endpoints that the service exposes.")
.example([
Expand All @@ -259,6 +263,16 @@ const serviceSchema = baseServiceSpecSchema
ports: joiArray(portSchema)
.unique("name")
.description("List of ports that the service container exposes."),
replicas: Joi.number()
.integer()
.min(1)
.default(1)
.description(deline`
The number of instances of the service to deploy.
Note: This setting may be overridden or ignored in some cases. For example, when running with \`daemon: true\`,
with hot-reloading enabled, or if the provider doesn't support multiple replicas.
`),
volumes: joiArray(volumeSchema)
.unique("name")
.description("List of volumes that should be mounted when deploying the container."),
Expand Down
Loading

0 comments on commit ad7c973

Please sign in to comment.