Skip to content
This repository has been archived by the owner on Mar 16, 2024. It is now read-only.

Commit

Permalink
Merge pull request #2298 from thedadams/pre-stop-hook
Browse files Browse the repository at this point in the history
Add pre-stop hooks for containers that expose ports
  • Loading branch information
thedadams authored Oct 27, 2023
2 parents 8f0e3f1 + b48a256 commit c0ac7e1
Show file tree
Hide file tree
Showing 84 changed files with 2,189 additions and 102 deletions.
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ FROM ghcr.io/acorn-io/images-mirror/tonistiigi/binfmt:qemu-v6.2.0 AS binfmt
FROM ghcr.io/acorn-io/images-mirror/moby/buildkit:v0.11.6 AS buildkit
FROM ghcr.io/acorn-io/images-mirror/registry:2.8.1 AS registry
FROM ghcr.io/acorn-io/images-mirror/rancher/klipper-lb:v0.3.5 AS klipper-lb
FROM ghcr.io/acorn-io/sleep:latest AS sleep

FROM ghcr.io/acorn-io/images-mirror/golang:1.21-alpine AS helper
WORKDIR /usr/src
Expand All @@ -20,7 +21,8 @@ RUN --mount=type=cache,target=/go/pkg --mount=type=cache,target=/root/.cache/go-
FROM ghcr.io/acorn-io/images-mirror/golang:1.21 AS build
COPY / /src
WORKDIR /src
RUN --mount=type=cache,target=/go/pkg --mount=type=cache,target=/root/.cache/go-build make build
COPY --from=sleep /sleep /src/pkg/controller/appdefinition/embed/acorn-sleep
RUN --mount=type=cache,target=/go/pkg --mount=type=cache,target=/root/.cache/go-build GO_TAGS=netgo,image make build

FROM ghcr.io/acorn-io/images-mirror/nginx:1.23.2-alpine AS base
RUN apk add --no-cache ca-certificates iptables ip6tables fuse3 git openssh pigz xz \
Expand Down
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
GO_TAGS ?= netgo
build:
CGO_ENABLED=0 go build -o bin/acorn -tags netgo -ldflags "-s -w" .
CGO_ENABLED=0 go build -o bin/acorn -tags "${GO_TAGS}" -ldflags "-s -w" .

tidy:
go mod tidy
Expand Down
64 changes: 55 additions & 9 deletions pkg/controller/appdefinition/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package appdefinition

import (
"crypto/sha256"
_ "embed"
"encoding/hex"
"encoding/json"
"errors"
Expand Down Expand Up @@ -118,6 +119,29 @@ func addDeployments(req router.Request, appInstance *v1.AppInstance, tag name.Re
if err != nil {
return err
}

outer:
for _, obj := range deps {
if dep, ok := obj.(*appsv1.Deployment); ok {
for _, v := range dep.Spec.Template.Spec.Volumes {
if v.Name == string(appInstance.UID) {
deps = append(deps, &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: string(appInstance.UID),
Namespace: appInstance.Status.Namespace,
Labels: map[string]string{
labels.AcornManaged: "true",
},
},
BinaryData: map[string][]byte{
string(appInstance.UID): acornSleepBinary,
},
})
break outer
}
}
}
}
resp.Objects(deps...)
return nil
}
Expand Down Expand Up @@ -205,7 +229,7 @@ func hasContextDir(container v1.Container) bool {
return false
}

func toContainers(app *v1.AppInstance, tag name.Reference, name string, container v1.Container, interpolator *secrets.Interpolator) ([]corev1.Container, []corev1.Container) {
func toContainers(app *v1.AppInstance, tag name.Reference, name string, container v1.Container, interpolator *secrets.Interpolator, addWait bool) ([]corev1.Container, []corev1.Container) {
var (
containers []corev1.Container
initContainers []corev1.Container
Expand All @@ -226,10 +250,10 @@ func toContainers(app *v1.AppInstance, tag name.Reference, name string, containe
})
}

newContainer := toContainer(app, tag, name, container, interpolator)
newContainer := toContainer(app, tag, name, container, interpolator, addWait && len(container.Ports) > 0)
containers = append(containers, newContainer)
for _, entry := range typed.Sorted(container.Sidecars) {
newContainer = toContainer(app, tag, entry.Key, entry.Value, interpolator)
newContainer = toContainer(app, tag, entry.Key, entry.Value, interpolator, addWait && len(entry.Value.Ports) > 0)

if entry.Value.Init {
initContainers = append(initContainers, newContainer)
Expand All @@ -254,7 +278,7 @@ func sanitizeVolumeName(name string) string {
return name
}

func toMounts(app *v1.AppInstance, container v1.Container, interpolation *secrets.Interpolator) (result []corev1.VolumeMount) {
func toMounts(app *v1.AppInstance, container v1.Container, interpolation *secrets.Interpolator, addWait bool) (result []corev1.VolumeMount) {
for _, entry := range typed.Sorted(container.Files) {
suffix := ""
if volume.NormalizeMode(entry.Value.Mode) != "" {
Expand Down Expand Up @@ -297,6 +321,13 @@ func toMounts(app *v1.AppInstance, container v1.Container, interpolation *secret
})
}
}

if addWait {
result = append(result, corev1.VolumeMount{
Name: string(app.UID),
MountPath: AcornHelperSleepPath,
})
}
return
}

Expand Down Expand Up @@ -420,7 +451,7 @@ func toProbe(container v1.Container, probeType v1.ProbeType) *corev1.Probe {
return nil
}

func toContainer(app *v1.AppInstance, tag name.Reference, containerName string, container v1.Container, interpolator *secrets.Interpolator) corev1.Container {
func toContainer(app *v1.AppInstance, tag name.Reference, containerName string, container v1.Container, interpolator *secrets.Interpolator, addWait bool) corev1.Container {
containerObject := corev1.Container{
Name: containerName,
Image: images.ResolveTag(tag, container.Image),
Expand All @@ -432,13 +463,26 @@ func toContainer(app *v1.AppInstance, tag name.Reference, containerName string,
TTY: container.Interactive,
Stdin: container.Interactive,
Ports: toPorts(container),
VolumeMounts: toMounts(app, container, interpolator),
VolumeMounts: toMounts(app, container, interpolator, addWait),
LivenessProbe: toProbe(container, v1.LivenessProbeType),
StartupProbe: toProbe(container, v1.StartupProbeType),
ReadinessProbe: toProbe(container, v1.ReadinessProbeType),
Resources: app.Status.Scheduling[containerName].Requirements,
}

if addWait {
// If a container exposes a port, then add a pre-stop lifecycle hook that sleeps for 5 seconds. This should allow the
// endpoints controller to remove the pods IP on termination and stop sending traffic to the container.
// Note that this requires the acorn-sleep binary to be in the container, via the volume mount.
containerObject.Lifecycle = &corev1.Lifecycle{
PreStop: &corev1.LifecycleHandler{
Exec: &corev1.ExecAction{
Command: []string{fmt.Sprintf("%s/%s", AcornHelperSleepPath, app.UID)},
},
},
}
}

return containerObject
}

Expand Down Expand Up @@ -636,18 +680,19 @@ func getSecretAnnotations(req router.Request, appInstance *v1.AppInstance, conta
func toDeployment(req router.Request, appInstance *v1.AppInstance, tag name.Reference, name string, container v1.Container, pullSecrets *PullSecrets, interpolator *secrets.Interpolator) (*appsv1.Deployment, error) {
var (
stateful = isStateful(appInstance, container)
addWait = !stateful && len(acornSleepBinary) > 0 && z.Dereference(container.Scale) > 1 && !appInstance.Status.GetDevMode()
)

interpolator = interpolator.ForContainer(name)

containers, initContainers := toContainers(appInstance, tag, name, container, interpolator)
containers, initContainers := toContainers(appInstance, tag, name, container, interpolator, addWait)

secretAnnotations, err := getSecretAnnotations(req, appInstance, container, interpolator)
if err != nil {
return nil, err
}

volumes, err := toVolumes(appInstance, container, interpolator)
volumes, err := toVolumes(appInstance, container, interpolator, addWait)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -685,7 +730,7 @@ func toDeployment(req router.Request, appInstance *v1.AppInstance, tag name.Refe
Affinity: appInstance.Status.Scheduling[name].Affinity,
Tolerations: appInstance.Status.Scheduling[name].Tolerations,
PriorityClassName: appInstance.Status.Scheduling[name].PriorityClassName,
TerminationGracePeriodSeconds: z.Pointer[int64](5),
TerminationGracePeriodSeconds: z.Pointer[int64](10),
ImagePullSecrets: pullSecrets.ForContainer(name, append(containers, initContainers...)),
EnableServiceLinks: new(bool),
Containers: containers,
Expand Down Expand Up @@ -733,6 +778,7 @@ func ToDeployments(req router.Request, appInstance *v1.AppInstance, tag name.Ref
if err != nil {
return nil, err
}

perms := v1.FindPermission(containerName, appInstance.Status.Permissions)
sa, err := toServiceAccount(req, dep.GetName(), dep.GetLabels(), dep.GetAnnotations(), appInstance, perms)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions pkg/controller/appdefinition/jobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func toJob(req router.Request, appInstance *v1.AppInstance, pullSecrets *PullSec
return nil, nil
}

containers, initContainers := toContainers(appInstance, tag, name, container, interpolator)
containers, initContainers := toContainers(appInstance, tag, name, container, interpolator, false)

containers = append(containers, corev1.Container{
Name: jobs.Helper,
Expand All @@ -123,7 +123,7 @@ func toJob(req router.Request, appInstance *v1.AppInstance, pullSecrets *PullSec
return nil, err
}

volumes, err := toVolumes(appInstance, container, interpolator)
volumes, err := toVolumes(appInstance, container, interpolator, false)
if err != nil {
return nil, err
}
Expand Down
22 changes: 22 additions & 0 deletions pkg/controller/appdefinition/pre_stop_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package appdefinition

import (
"testing"

"github.com/acorn-io/baaah/pkg/router/tester"
"github.com/acorn-io/runtime/pkg/scheme"
)

func TestPreStop(t *testing.T) {
acornSleepBinary = []byte("acorn-sleep")
t.Cleanup(func() {
acornSleepBinary = nil
})

tester.DefaultTest(t, scheme.Scheme, "testdata/deployspec/pre-stop/basic", DeploySpec)
tester.DefaultTest(t, scheme.Scheme, "testdata/deployspec/pre-stop/stateful", DeploySpec)
tester.DefaultTest(t, scheme.Scheme, "testdata/deployspec/pre-stop/job", DeploySpec)
tester.DefaultTest(t, scheme.Scheme, "testdata/deployspec/pre-stop/dev", DeploySpec)
tester.DefaultTest(t, scheme.Scheme, "testdata/deployspec/pre-stop/no-ports", DeploySpec)
tester.DefaultTest(t, scheme.Scheme, "testdata/deployspec/pre-stop/ports-only-sidecar", DeploySpec)
}
13 changes: 12 additions & 1 deletion pkg/controller/appdefinition/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func toRouter(appInstance *v1.AppInstance, routerName string, router v1.Router)
Annotations: deploymentAnnotations,
},
Spec: corev1.PodSpec{
TerminationGracePeriodSeconds: z.Pointer[int64](5),
TerminationGracePeriodSeconds: z.Pointer[int64](10),
EnableServiceLinks: new(bool),
Containers: []corev1.Container{
{
Expand Down Expand Up @@ -110,6 +110,17 @@ func toRouter(appInstance *v1.AppInstance, routerName string, router v1.Router)
},
},
},
Lifecycle: &corev1.Lifecycle{
PreStop: &corev1.LifecycleHandler{
Exec: &corev1.ExecAction{
Command: []string{
"/bin/sh",
"-c",
"sleep 5 && /usr/sbin/nginx -s quit",
},
},
},
},
},
},
Volumes: []corev1.Volume{
Expand Down
6 changes: 6 additions & 0 deletions pkg/controller/appdefinition/sleep_dev.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//go:build !image

package appdefinition

// If the binary is being built on its own and not part of an image, then don't worry about this binary.
var acornSleepBinary []byte
8 changes: 8 additions & 0 deletions pkg/controller/appdefinition/sleep_image.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//go:build image

package appdefinition

import _ "embed"

//go:embed embed/acorn-sleep
var acornSleepBinary []byte
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ spec:
imagePullSecrets:
- name: oneimage-pull-1234567890ab
serviceAccountName: oneimage
terminationGracePeriodSeconds: 5
terminationGracePeriodSeconds: 10
status: {}

---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ spec:
imagePullSecrets:
- name: oneimage-pull-1234567890ab
serviceAccountName: oneimage
terminationGracePeriodSeconds: 5
terminationGracePeriodSeconds: 10
status: {}

---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ spec:
imagePullSecrets:
- name: oneimage-pull-1234567890ab
serviceAccountName: oneimage
terminationGracePeriodSeconds: 5
terminationGracePeriodSeconds: 10
status: {}

---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ spec:
imagePullSecrets:
- name: oneimage-pull-1234567890ab
serviceAccountName: oneimage
terminationGracePeriodSeconds: 5
terminationGracePeriodSeconds: 10
status: {}

---
Expand Down Expand Up @@ -198,7 +198,7 @@ spec:
imagePullSecrets:
- name: twoimage-pull-1234567890ab
serviceAccountName: twoimage
terminationGracePeriodSeconds: 5
terminationGracePeriodSeconds: 10
status: {}

---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ spec:
imagePullSecrets:
- name: oneimage-pull-1234567890ab
serviceAccountName: oneimage
terminationGracePeriodSeconds: 5
terminationGracePeriodSeconds: 10
status: {}

---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ spec:
imagePullSecrets:
- name: oneimage-pull-1234567890ab
serviceAccountName: oneimage
terminationGracePeriodSeconds: 5
terminationGracePeriodSeconds: 10
status: {}

---
Expand Down Expand Up @@ -184,7 +184,7 @@ spec:
imagePullSecrets:
- name: twoimage-pull-1234567890ab
serviceAccountName: twoimage
terminationGracePeriodSeconds: 5
terminationGracePeriodSeconds: 10
status: {}

---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ spec:
imagePullSecrets:
- name: oneimage-pull-1234567890ab
serviceAccountName: oneimage
terminationGracePeriodSeconds: 5
terminationGracePeriodSeconds: 10
status: {}

---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ spec:
imagePullSecrets:
- name: container-name-pull-1234567890ab
serviceAccountName: container-name
terminationGracePeriodSeconds: 5
terminationGracePeriodSeconds: 10
status: {}

---
Expand Down Expand Up @@ -158,7 +158,7 @@ spec:
imagePullSecrets:
- name: web-pull-1234567890ab
serviceAccountName: web
terminationGracePeriodSeconds: 5
terminationGracePeriodSeconds: 10
status: {}

---
Expand Down
4 changes: 2 additions & 2 deletions pkg/controller/appdefinition/testdata/depends/expected.golden
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ spec:
imagePullSecrets:
- name: container-name-pull-1234567890ab
serviceAccountName: container-name
terminationGracePeriodSeconds: 5
terminationGracePeriodSeconds: 10
status: {}

---
Expand Down Expand Up @@ -162,7 +162,7 @@ spec:
imagePullSecrets:
- name: web-pull-1234567890ab
serviceAccountName: web
terminationGracePeriodSeconds: 5
terminationGracePeriodSeconds: 10
status: {}

---
Expand Down
Loading

0 comments on commit c0ac7e1

Please sign in to comment.