Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: single sidecars exe and versioned templates #745

Merged
merged 17 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 0 additions & 13 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,3 @@ jobs:
make test-e2e
push: never
skipContainerUserIdUpdate: false

run-authproxy-unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Tests
uses: devcontainers/[email protected]
with:
runCmd: |
cd authproxy
make test
push: never
skipContainerUserIdUpdate: false
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ COPY go.sum go.sum
RUN go mod download

# Copy the go source
COPY cmd/main.go cmd/main.go
COPY cmd/amalthea/main.go cmd/amalthea/main.go
COPY api/ api/
COPY internal/controller/ internal/controller/
COPY internal/ internal/

# Build
# the GOARCH has not a default value to allow the binary be built according to the host where the command
# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/amalthea/main.go

# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
Expand Down
18 changes: 16 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ IMAGE_TAG_BASE ?= renku/amalthea
# BUNDLE_IMG defines the image:tag used for the bundle.
# You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=<some-registry>/<project-name-bundle>:<tag>)
BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:v$(VERSION)
SIDECARS_IMG ?= $(IMAGE_TAG_BASE)-sidecars:v$(VERSION)

# BUNDLE_GEN_FLAGS are the flags passed to the operator-sdk generate bundle command
BUNDLE_GEN_FLAGS ?= -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS)
Expand Down Expand Up @@ -89,6 +90,8 @@ all: build
# More info on the awk command:
# http://linuxcommand.org/lc3_adv_awk.php

HELM_CRD_TEMPLATE ?= helm-chart/amalthea-sessions/templates/amaltheasession-crd.yaml

.PHONY: help
help: ## Display this help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
Expand All @@ -98,6 +101,9 @@ help: ## Display this help.
.PHONY: manifests
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
echo "{{- if .Values.deployCrd -}}" > $(HELM_CRD_TEMPLATE)
echo "# This manifest is auto-generated from the makefile do not edit manually." >> $(HELM_CRD_TEMPLATE)
cat config/crd/bases/*yaml >> $(HELM_CRD_TEMPLATE)

.PHONY: generate
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
Expand Down Expand Up @@ -140,11 +146,19 @@ lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes

.PHONY: build
build: manifests generate fmt vet ## Build manager binary.
go build -o bin/manager cmd/main.go
go build -o bin/manager cmd/amalthea/main.go

.PHONY: build-sidecars
build-sidecars: fmt vet
go build -o bin/sidecars cmd/sidecars/main.go

.PHONY: build-sidecars
docker-build-sidecars: build-sidecars
$(CONTAINER_TOOL) build -t ${SIDECARS_IMG} -f sidecars.Dockerfile .

.PHONY: run
run: manifests generate fmt vet ## Run a controller from your host.
go run ./cmd/main.go
go run ./cmd/amalthea/main.go

# If you wish to build the manager image targeting other platforms you can use the --platform flag.
# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it.
Expand Down
145 changes: 15 additions & 130 deletions api/v1alpha1/amaltheasession_children.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"net/url"
"os"
"strings"
"time"

appsv1 "k8s.io/api/apps/v1"
Expand All @@ -29,16 +28,14 @@ const servicePort int32 = 80
const sessionVolumeName string = prefix + "volume"
const shmVolumeName string = prefix + "dev-shm"
const authProxyPort int32 = 65535
const oauth2ProxyImage = "bitnami/oauth2-proxy:7.6.0"
const authProxyImage = "renku/authproxy:0.0.1-test-1"

var rcloneStorageClass string = getStorageClass()
var rcloneDefaultStorage resource.Quantity = resource.MustParse("1Gi")

const rcloneStorageSecretNameAnnotation = "csi-rclone.dev/secretName"

// StatefulSet returns a AmaltheaSession StatefulSet object
func (cr *AmaltheaSession) StatefulSet() appsv1.StatefulSet {
func (cr *AmaltheaSession) StatefulSet() (appsv1.StatefulSet, error) {
labels := labelsForAmaltheaSession(cr.Name)
replicas := int32(1)
if cr.Spec.Hibernated {
Expand Down Expand Up @@ -104,9 +101,13 @@ func (cr *AmaltheaSession) StatefulSet() appsv1.StatefulSet {
initContainers := []v1.Container{}

if len(cr.Spec.CodeRepositories) > 0 {
gitCloneContainers, gitCloneVols := cr.initClones()
initContainers = append(initContainers, gitCloneContainers...)
volumes = append(volumes, gitCloneVols...)
templateFunc, err := initCloneTemplate.GetFunc(cr.Spec.Sidecars.Image)
if err != nil {
return appsv1.StatefulSet{}, err
}
cloneManifests := templateFunc(cr)
initContainers = append(initContainers, cloneManifests.Containers...)
volumes = append(volumes, cloneManifests.Volumes...)
}

initContainers = append(initContainers, cr.Spec.ExtraInitContainers...)
Expand Down Expand Up @@ -141,84 +142,13 @@ func (cr *AmaltheaSession) StatefulSet() appsv1.StatefulSet {
containers := []v1.Container{sessionContainer}
containers = append(containers, cr.Spec.ExtraContainers...)

if auth := cr.Spec.Authentication; auth != nil && auth.Enabled {
extraAuthMounts := []v1.VolumeMount{}
if len(auth.ExtraVolumeMounts) > 0 {
extraAuthMounts = auth.ExtraVolumeMounts
}
volumes = append(volumes, v1.Volume{
Name: "proxy-configuration-secret",
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: auth.SecretRef.Name,
Optional: ptr.To(false),
},
},
})

if auth.Type == Oidc {
sessionURL := cr.sessionLocalhostURL().String()
if !strings.HasSuffix(sessionURL, "/") {
// NOTE: If the url does not end with "/" then the oauth2proxy proxies only the exact path
// and does not proxy subpaths
sessionURL += "/"
}
authContainer := v1.Container{
Image: oauth2ProxyImage,
Name: "oauth2-proxy",
SecurityContext: &v1.SecurityContext{
AllowPrivilegeEscalation: ptr.To(false),
RunAsNonRoot: ptr.To(true),
},
Args: []string{
fmt.Sprintf("--upstream=%s", sessionURL),
fmt.Sprintf("--http-address=:%d", authProxyPort),
"--silence-ping-logging",
"--config=/etc/oauth2-proxy/" + auth.SecretRef.Key,
},
VolumeMounts: append(
[]v1.VolumeMount{
{
Name: "proxy-configuration-secret",
MountPath: "/etc/oauth2-proxy",
},
},
extraAuthMounts...,
),
}

containers = append(containers, authContainer)
} else if auth.Type == Token {
authContainer := v1.Container{
Image: authProxyImage,
Name: "authproxy",
SecurityContext: &v1.SecurityContext{
AllowPrivilegeEscalation: ptr.To(false),
RunAsNonRoot: ptr.To(true),
RunAsUser: ptr.To(int64(1000)),
RunAsGroup: ptr.To(int64(1000)),
},
Args: []string{"serve", "--config", "/etc/authproxy/" + auth.SecretRef.Key},
Env: []v1.EnvVar{
{Name: "AUTHPROXY_PORT", Value: fmt.Sprintf("%d", authProxyPort)},
// NOTE: The url for the remote has to not have a path at all, if it does, then the path
// in the url is appended to any path that is already there when the request comes in.
{Name: "AUTHPROXY_REMOTE", Value: fmt.Sprintf("http://127.0.0.1:%d", cr.Spec.Session.Port)},
},
VolumeMounts: append(
[]v1.VolumeMount{
{
Name: "proxy-configuration-secret",
MountPath: "/etc/authproxy",
},
},
extraAuthMounts...,
),
}

containers = append(containers, authContainer)
}
authTemplateFn, err := authTemplate.GetFunc(cr.Spec.Sidecars.Image)
if err != nil {
return appsv1.StatefulSet{}, err
}
authManifests := authTemplateFn(cr)
containers = append(containers, authManifests.Containers...)
volumes = append(volumes, authManifests.Volumes...)

sts := appsv1.StatefulSet{
ObjectMeta: metav1.ObjectMeta{
Expand Down Expand Up @@ -249,7 +179,7 @@ func (cr *AmaltheaSession) StatefulSet() appsv1.StatefulSet {
},
},
}
return sts
return sts, nil
}

// Service returns a AmaltheaSession Service object
Expand Down Expand Up @@ -407,51 +337,6 @@ func (cr *AmaltheaSession) Pod(ctx context.Context, clnt client.Client) (*v1.Pod
return &pod, err
}

// Generates the init containers that clones the specified Git repositories
func (cr *AmaltheaSession) initClones() ([]v1.Container, []v1.Volume) {
envVars := []v1.EnvVar{}
volMounts := []v1.VolumeMount{{Name: sessionVolumeName, MountPath: cr.Spec.Session.Storage.MountPath}}
vols := []v1.Volume{}
containers := []v1.Container{}

for irepo, repo := range cr.Spec.CodeRepositories {
args := []string{"clone", "--strategy", "notifexist", "--remote", repo.Remote, "--path", cr.Spec.Session.Storage.MountPath + "/" + repo.ClonePath}

if repo.CloningConfigSecretRef != nil {
secretVolName := fmt.Sprintf("git-clone-cred-volume-%d", irepo)
secretMountPath := "/git-clone-secrets"
secretFilePath := fmt.Sprintf("%s/%s", secretMountPath, repo.CloningConfigSecretRef.Key)
vols = append(
vols,
v1.Volume{
Name: secretVolName,
VolumeSource: v1.VolumeSource{Secret: &v1.SecretVolumeSource{SecretName: repo.CloningConfigSecretRef.Name}},
},
)
volMounts = append(volMounts, v1.VolumeMount{Name: secretVolName, MountPath: secretMountPath})

args = append(args, []string{"--config", secretFilePath}...)
}

if repo.Revision != "" {
args = append(args, []string{"--revision", repo.Revision}...)
}

gitCloneContainerName := fmt.Sprintf("git-clone-%d", irepo)
containers = append(containers, v1.Container{
Name: gitCloneContainerName,
Image: "renku/cloner:0.0.1",
VolumeMounts: volMounts,
WorkingDir: cr.Spec.Session.Storage.MountPath,
Env: envVars,
SecurityContext: &v1.SecurityContext{RunAsUser: &cr.Spec.Session.RunAsUser, RunAsGroup: &cr.Spec.Session.RunAsGroup},
Args: args,
})
}

return containers, vols
}

// Returns the list of all the secrets used in this CR
func (cr *AmaltheaSession) AdoptedSecrets() v1.SecretList {
secrets := v1.SecretList{}
Expand Down
12 changes: 12 additions & 0 deletions api/v1alpha1/amaltheasession_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ type AmaltheaSessionSpec struct {
// Passed right through to the Statefulset used for the session.
// +optional
Tolerations []v1.Toleration `json:"tolerations,omitempty"`

//Control over the sidecars and init containers Amalthea adds to each session
Sidecars Sidecars `json:"sidecars,omitempty"`
}

type Session struct {
Expand Down Expand Up @@ -416,3 +419,12 @@ func (a *AmaltheaSession) GetURL() *url.URL {
}
return &sessionURL
}

type Sidecars struct {
// The docker image with the sidecars CLI.
// The containers that are templated are decided based on the image version tag, falling back
// on the latest templates for the latest version. Using a non-official image here is strongly
// discouraged, if you must then you should use the same semver tags as the official image you
// started with or based your custom image on.
Image string `json:"image,omitempty"`
}
Loading
Loading