Compare commits
5 Commits
b02a7a6bc2
...
f7683be745
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7683be745 | ||
|
|
86eb2002f0 | ||
|
|
d204047979 | ||
|
|
7acdc5e970 | ||
|
|
54ca0e3062 |
47
README.md
47
README.md
@ -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
20
gitops/root-app.yaml
Normal 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
|
||||||
37
gitops/tenants-appset.yaml
Normal file
37
gitops/tenants-appset.yaml
Normal 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
|
||||||
15
gitops/tenants-project.yaml
Normal file
15
gitops/tenants-project.yaml
Normal 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
22
images/base/dockerfile
Normal 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
24
images/jupyter/dockerfile
Normal 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"]
|
||||||
4
images/jupyter/requirements.txt
Normal file
4
images/jupyter/requirements.txt
Normal 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
46
minio/manifests.yaml
Normal 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
|
||||||
19
tenants/tenant-a/values.yaml
Normal file
19
tenants/tenant-a/values.yaml
Normal 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
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user