Compare commits

...

5 Commits

Author SHA1 Message Date
Adrien Bouvais
f7683be745 Removed unecessary config 2026-08-14 16:02:14 +02:00
Adrien Bouvais
86eb2002f0 Added mioni manifests 2026-08-14 16:01:50 +02:00
Adrien Bouvais
d204047979 Add gitops 2026-08-14 16:01:42 +02:00
Adrien Bouvais
7acdc5e970 Added base config for tenant-a 2026-08-14 14:31:01 +02:00
Adrien Bouvais
54ca0e3062 Added images 2026-08-14 14:29:19 +02:00
9 changed files with 232 additions and 2 deletions

View File

@ -13,12 +13,17 @@ brew install docker
# 2. Images # 2. Images
``` To created the needed dependency, I did a simple 2 images base + jupyter.
The first image is a minimal python slim. I then add some
### 2.1. Base
```images/base/dockerfile
FROM python:3.12-slim-bookworm AS base FROM python:3.12-slim-bookworm AS base
LABEL org.opencontainers.image.title="tenant-base" \ LABEL org.opencontainers.image.title="tenant-base" \
org.opencontainers.image.description="Hardened base image for tenant workspaces" \ org.opencontainers.image.description="Hardened base image for tenant workspaces" \
org.opencontainers.image.source="https://github.com/yourorg/yourrepo" org.opencontainers.image.source="https://git.bouvais.lu/adrien/"
# System deps only — keep this layer stable so it's rarely rebuilt # System deps only — keep this layer stable so it's rarely rebuilt
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
@ -36,3 +41,41 @@ USER appuser
ENTRYPOINT ["tini", "--"] ENTRYPOINT ["tini", "--"]
``` ```
Then build and push it to the registry
```
docker build -t registry.bouvais.lu/tenant-base:1.0.0 images/base
docker push registry.bouvais.lu/tenant-base:1.0.0
```
### 2.2. Jupyter
Now I dp the same for a simple jupyter image.
```
ARG BASE_IMAGE=registry.bouvais.lu/tenant-base:1.0.0
FROM ${BASE_IMAGE}
LABEL org.opencontainers.image.title="tenant-jupyter" \
org.opencontainers.image.description="JupyterLab image built on tenant-base" \
org.opencontainers.image.base.name="${BASE_IMAGE}"
USER root
COPY --chown=appuser:appuser requirements.txt /tmp/requirements.txt
RUN pip install --no-cache-dir -r /tmp/requirements.txt \
&& rm /tmp/requirements.txt
# No secrets baked in — S3 creds come from a mounted K8s Secret / env at runtime
USER appuser
WORKDIR /home/appuser/work
EXPOSE 8888
CMD ["jupyter", "lab", \
"--ip=0.0.0.0", \
"--port=8888", \
"--no-browser", \
"--ServerApp.token=", \
"--ServerApp.allow_remote_access=True"]
```

20
gitops/root-app.yaml Normal file
View File

@ -0,0 +1,20 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root
namespace: argocd
spec:
project: default
source:
repoURL: https://git.bouvais.lu/adrien/ctie-exercice
targetRevision: main
path: gitops
directory:
recurse: true
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true

View File

@ -0,0 +1,37 @@
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: tenants
namespace: argocd
spec:
goTemplate: true
generators:
- git:
repoURL: https://git.bouvais.lu/adrien/ctie-exercice
revision: main
files:
- path: "tenants/*/config.yaml"
template:
metadata:
name: 'tenant-{{.name}}'
spec:
project: tenants
sources:
- repoURL: https://git.bouvais.lu/adrien/ctie-exercice
targetRevision: main
path: charts/tenant
helm:
valueFiles:
- '$values/tenants/{{.name}}/config.yaml'
- repoURL: https://git.bouvais.lu/adrien/ctie-exercice
targetRevision: main
ref: values
destination:
server: https://kubernetes.default.svc
namespace: 'tenant-{{.name}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true

View File

@ -0,0 +1,15 @@
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: tenants
namespace: argocd
spec:
sourceRepos:
- https://git.bouvais.lu/adrien/ctie-exercice
destinations:
- server: https://kubernetes.default.svc
namespace: 'tenant-*'
clusterResourceWhitelist: [] # tenants can't touch cluster-scoped resources
namespaceResourceWhitelist:
- group: '*'
kind: '*'

22
images/base/dockerfile Normal file
View File

@ -0,0 +1,22 @@
FROM python:3.12-slim-bookworm AS base
LABEL org.opencontainers.image.title="tenant-base" \
org.opencontainers.image.description="Hardened base image for tenant workspaces" \
org.opencontainers.image.source="https://git.bouvais.lu/adrien/"
# System deps only — keep this layer stable so it's rarely rebuilt
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
curl \
tini \
&& rm -rf /var/lib/apt/lists/*
# Non-root user, fixed UID/GID for predictable K8s securityContext
RUN groupadd --gid 1000 appuser \
&& useradd --uid 1000 --gid appuser --shell /bin/bash --create-home appuser
WORKDIR /home/appuser
USER appuser
ENTRYPOINT ["tini", "--"]

24
images/jupyter/dockerfile Normal file
View File

@ -0,0 +1,24 @@
ARG BASE_IMAGE=registry.bouvais.lu/tenant-base:1.0.0
FROM ${BASE_IMAGE}
LABEL org.opencontainers.image.title="tenant-jupyter" \
org.opencontainers.image.description="JupyterLab image built on tenant-base" \
org.opencontainers.image.base.name="${BASE_IMAGE}"
USER root
COPY --chown=appuser:appuser requirements.txt /tmp/requirements.txt
RUN pip install --no-cache-dir -r /tmp/requirements.txt \
&& rm /tmp/requirements.txt
# No secrets baked in — S3 creds come from a mounted K8s Secret / env at runtime
USER appuser
WORKDIR /home/appuser/work
EXPOSE 8888
CMD ["jupyter", "lab", \
"--ip=0.0.0.0", \
"--port=8888", \
"--no-browser", \
"--ServerApp.token=", \
"--ServerApp.allow_remote_access=True"]

View File

@ -0,0 +1,4 @@
jupyterlab==4.2.5
boto3==1.35.0
s3fs==2024.9.0
pandas==2.2.2

46
minio/manifests.yaml Normal file
View File

@ -0,0 +1,46 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: minio
namespace: minio
spec:
replicas: 1
selector:
matchLabels: {app: minio}
template:
metadata:
labels: {app: minio}
spec:
containers:
- name: minio
image: minio/minio:latest
args: ["server", "/data", "--console-address", ":9001"]
env:
- name: MINIO_ROOT_USER
value: "admin"
- name: MINIO_ROOT_PASSWORD
value: "changeme123" # TODO: Remove
ports:
- containerPort: 9000
- containerPort: 9001
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
emptyDir: {} # TODO: Make it persistant
---
apiVersion: v1
kind: Service
metadata:
name: minio
namespace: minio
spec:
selector: {app: minio}
ports:
- name: api
port: 9000
targetPort: 9000
- name: console
port: 9001
targetPort: 9001

View File

@ -0,0 +1,19 @@
name: tenant-a
image:
repository: registry.bouvais.lu/tenant-jupyter
tag: "1.0.0"
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: "1"
memory: 2Gi
gpu:
enabled: true
type: "t4" # one of: none | t4 | a100 | l4
count: 1