Skip to content

Commit

Permalink
feat(k8s): support service and ingress annotations on container module
Browse files Browse the repository at this point in the history
  • Loading branch information
edvald committed Feb 27, 2019
1 parent b2ac853 commit 894bd1f
Show file tree
Hide file tree
Showing 10 changed files with 218 additions and 166 deletions.
22 changes: 20 additions & 2 deletions docs/reference/module-types/container.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@ The names of any services that this service depends on at runtime, and the names
| Type | Required |
| ---- | -------- |
| `array[string]` | No
### `module.services[].annotations`
[module](#module) > [services](#module.services[]) > annotations

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

| Type | Required |
| ---- | -------- |
| `object` | No
### `module.services[].args[]`
[module](#module) > [services](#module.services[]) > args

Expand Down Expand Up @@ -147,6 +155,14 @@ module:
- path: /api
port: http
```
### `module.services[].ingresses[].annotations`
[module](#module) > [services](#module.services[]) > [ingresses](#module.services[].ingresses[]) > annotations

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

| Type | Required |
| ---- | -------- |
| `object` | No
### `module.services[].ingresses[].hostname`
[module](#module) > [services](#module.services[]) > [ingresses](#module.services[].ingresses[]) > hostname

Expand Down Expand Up @@ -273,7 +289,7 @@ The protocol of the port.
### `module.services[].ports[].containerPort`
[module](#module) > [services](#module.services[]) > [ports](#module.services[].ports[]) > containerPort

The port exposed on the container by the running procces. This will also be the default value for `servicePort`.
The port exposed on the container by the running process. This will also be the default value for `servicePort`.
`servicePort:80 -> containerPort:8080 -> process:8080`

| Type | Required |
Expand Down Expand Up @@ -485,10 +501,12 @@ module:
services:
- name:
dependencies: []
annotations: {}
args:
daemon: false
ingresses:
- hostname:
- annotations: {}
hostname:
path: /
port:
env: {}
Expand Down
19 changes: 17 additions & 2 deletions garden-service/src/plugins/container/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ import { ModuleSpec, ModuleConfig } from "../../config/module"
import { CommonServiceSpec, ServiceConfig, baseServiceSchema } from "../../config/service"
import { baseTaskSpecSchema, BaseTaskSpec } from "../../config/task"
import { baseTestSpecSchema, BaseTestSpec } from "../../config/test"
import { joiStringMap } from "../../config/common"

export interface ContainerIngressSpec {
annotations: Annotations
hostname?: string
path: string
port: string
Expand Down Expand Up @@ -59,7 +61,12 @@ export interface ServiceHealthCheckSpec {
tcpPort?: string,
}

interface Annotations {
[name: string]: string
}

export interface ContainerServiceSpec extends CommonServiceSpec {
annotations: Annotations,
args: string[],
daemon: boolean
ingresses: ContainerIngressSpec[],
Expand Down Expand Up @@ -107,8 +114,13 @@ const hotReloadConfigSchema = Joi.object()

export type ContainerServiceConfig = ServiceConfig<ContainerServiceSpec>

const annotationsSchema = joiStringMap(Joi.string())
.default(() => ({}), "{}")

const ingressSchema = Joi.object()
.keys({
annotations: annotationsSchema
.description("Annotations to attach to the ingress (Note: May not be applicable to all providers)"),
hostname: ingressHostnameSchema,
path: Joi.string().uri(<any>{ relativeOnly: true })
.default("/")
Expand Down Expand Up @@ -151,11 +163,12 @@ export const portSchema = Joi.object()
.required()
.example("8080")
.description(deline`
The port exposed on the container by the running procces. This will also be the default value
The port exposed on the container by the running process. This will also be the default value
for \`servicePort\`.
\`servicePort:80 -> containerPort:8080 -> process:8080\``),
servicePort: Joi.number().default((context) => context.containerPort, "<containerPort>")
servicePort: Joi.number()
.default((context) => context.containerPort, "<containerPort>")
.example("80")
.description(deline`The port exposed on the service.
Defaults to \`containerPort\` if not specified.
Expand Down Expand Up @@ -183,6 +196,8 @@ const volumeSchema = Joi.object()

const serviceSchema = baseServiceSchema
.keys({
annotations: annotationsSchema
.description("Annotations to attach to the service (Note: May not be applicable to all providers)"),
args: Joi.array().items(Joi.string())
.description("The arguments to run the container with when starting the service."),
daemon: Joi.boolean()
Expand Down
8 changes: 4 additions & 4 deletions garden-service/src/plugins/kubernetes/container/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import { extend, keyBy, set, toPairs } from "lodash"
import { DeployServiceParams, PushModuleParams, DeleteServiceParams } from "../../../types/plugin/params"
import { RuntimeContext, Service, ServiceStatus } from "../../../types/service"
import { ContainerModule, ContainerService } from "../../container/config"
import { createIngresses } from "./ingress"
import { createServices } from "./service"
import { createIngressResources } from "./ingress"
import { createServiceResources } from "./service"
import { waitForResources } from "../status"
import { applyMany, deleteObjectsByLabel } from "../kubectl"
import { getAppNamespace } from "../namespace"
Expand Down Expand Up @@ -53,9 +53,9 @@ export async function createContainerObjects(
const version = service.module.version
const namespace = await getAppNamespace(ctx, ctx.provider)
const api = new KubeApi(ctx.provider)
const ingresses = await createIngresses(api, namespace, service)
const ingresses = await createIngressResources(api, namespace, service)
const deployment = await createDeployment(ctx.provider, service, runtimeContext, namespace, enableHotReload)
const kubeservices = await createServices(service, namespace)
const kubeservices = await createServiceResources(service, namespace)

const objects = [deployment, ...kubeservices, ...ingresses]

Expand Down
26 changes: 11 additions & 15 deletions garden-service/src/plugins/kubernetes/container/ingress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import * as Bluebird from "bluebird"
import { certpem } from "certpem"
import { groupBy, omit, find } from "lodash"
import { omit, find, extend } from "lodash"
import { findByName } from "../../../util/util"
import { ContainerService, ContainerIngressSpec } from "../../container/config"
import { IngressTlsCertificate } from "../kubernetes"
Expand All @@ -24,34 +24,28 @@ interface ServiceIngressWithCert extends ServiceIngress {

const certificateHostnames: { [name: string]: string[] } = {}

export async function createIngresses(api: KubeApi, namespace: string, service: ContainerService) {
export async function createIngressResources(api: KubeApi, namespace: string, service: ContainerService) {
if (service.spec.ingresses.length === 0) {
return []
}

const allIngresses = await getIngressesWithCert(service, api)

// first group ingress endpoints by certificate, so we can properly configure TLS
const groupedByCert = groupBy(allIngresses, e => e.certificate ? e.certificate.name : undefined)

return Bluebird.map(Object.values(groupedByCert), async (certIngresses) => {
// second, group ingress endpoints by hostname
const groupedByHostname = groupBy(certIngresses, e => e.hostname)

const rules = Object.entries(groupedByHostname).map(([host, hostnameIngresses]) => ({
host,
return Bluebird.map(allIngresses, async (ingress) => {
const rules = [{
host: ingress.hostname,
http: {
paths: hostnameIngresses.map(ingress => ({
paths: [{
path: ingress.path,
backend: {
serviceName: service.name,
servicePort: findByName(service.spec.ports, ingress.spec.port)!.servicePort,
},
})),
}],
},
}))
}]

const cert = certIngresses[0].certificate
const cert = ingress.certificate

const annotations = {
"ingress.kubernetes.io/force-ssl-redirect": !!cert + "",
Expand All @@ -61,6 +55,8 @@ export async function createIngresses(api: KubeApi, namespace: string, service:
annotations["kubernetes.io/ingress.class"] = api.provider.config.ingressClass
}

extend(annotations, ingress.spec.annotations)

const spec: any = { rules }

if (!!cert) {
Expand Down
4 changes: 2 additions & 2 deletions garden-service/src/plugins/kubernetes/container/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import { ContainerService } from "../../container/config"

export async function createServices(service: ContainerService, namespace: string) {
export async function createServiceResources(service: ContainerService, namespace: string) {
const services: any = []

const addService = (name: string, type: string, servicePorts: any[]) => {
Expand All @@ -17,7 +17,7 @@ export async function createServices(service: ContainerService, namespace: strin
kind: "Service",
metadata: {
name,
annotations: {},
annotations: service.spec.annotations,
namespace,
},
spec: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,12 @@ export const gardenPlugin = (): GardenPlugin => ({
outputs: {
ingress: `http://${s.name}:${emulatorPort}/local/local/${functionEntrypoint}`,
},
annotations: {},
args: ["/app/start.sh", functionEntrypoint],
daemon: false,
ingresses: [{
name: "default",
annotations: {},
hostname: s.spec.hostname,
port: "http",
path: "/",
Expand Down
10 changes: 10 additions & 0 deletions garden-service/test/src/plugins/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,11 +201,13 @@ describe("plugins.container", () => {
buildArgs: {},
services: [{
name: "service-a",
annotations: {},
args: ["echo"],
dependencies: [],
daemon: false,
ingresses: [
{
annotations: {},
path: "/",
port: "http",
},
Expand Down Expand Up @@ -264,10 +266,12 @@ describe("plugins.container", () => {
services:
[{
name: "service-a",
annotations: {},
args: ["echo"],
dependencies: [],
daemon: false,
ingresses: [{
annotations: {},
path: "/",
port: "http",
}],
Expand Down Expand Up @@ -304,10 +308,12 @@ describe("plugins.container", () => {
spec:
{
name: "service-a",
annotations: {},
args: ["echo"],
dependencies: [],
daemon: false,
ingresses: [{
annotations: {},
path: "/",
port: "http",
}],
Expand Down Expand Up @@ -380,11 +386,13 @@ describe("plugins.container", () => {
buildArgs: {},
services: [{
name: "service-a",
annotations: {},
args: ["echo"],
dependencies: [],
daemon: false,
ingresses: [
{
annotations: {},
path: "/",
port: "bla",
},
Expand Down Expand Up @@ -437,6 +445,7 @@ describe("plugins.container", () => {
buildArgs: {},
services: [{
name: "service-a",
annotations: {},
args: ["echo"],
dependencies: [],
daemon: false,
Expand Down Expand Up @@ -489,6 +498,7 @@ describe("plugins.container", () => {
buildArgs: {},
services: [{
name: "service-a",
annotations: {},
args: ["echo"],
dependencies: [],
daemon: false,
Expand Down
Loading

0 comments on commit 894bd1f

Please sign in to comment.