app/registry: initial docker registry setup
diff --git a/app/registry/prod.jsonnet b/app/registry/prod.jsonnet
new file mode 100644
index 0000000..0b7fea5
--- /dev/null
+++ b/app/registry/prod.jsonnet
@@ -0,0 +1,240 @@
+local kube = import "../../kube/kube.libsonnet";
+local cm = import "../../cluster/kube/lib/cert-manager.libsonnet";
+
+{
+ local app = self,
+ local cfg = app.cfg,
+ cfg:: {
+ namespace: "registry",
+ domain: "k0.hswaw.net",
+ },
+
+ metadata(component):: {
+ namespace: cfg.namespace,
+ labels: {
+ "app.kubernetes.io/name": "registry",
+ "app.kubernetes.io/managed-by": "kubecfg",
+ "app.kubernetes.io/component": component,
+ },
+ },
+
+ namespace: kube.Namespace(cfg.namespace),
+
+ registryIssuer: cm.Issuer("registry-issuer") {
+ metadata+: app.metadata("registry-issuer"),
+ spec: {
+ selfSigned: {},
+ },
+ },
+ authCertificate: cm.Certificate("auth") {
+ metadata+: app.metadata("auth"),
+ spec: {
+ secretName: "auth-internal",
+ duration: "43800h0m0s", // 5 years
+ issuerRef: {
+ name: app.registryIssuer.metadata.name,
+ },
+ commonName: "auth.registry",
+ },
+ },
+ registryCertificate: cm.Certificate("registry") {
+ metadata+: app.metadata("registry"),
+ spec: {
+ secretName: "registry-internal",
+ duration: "43800h0m0s", // 5 years
+ issuerRef: {
+ name: app.registryIssuer.metadata.name,
+ },
+ commonName: "registry.registry",
+ },
+ },
+
+ registryConfig: kube.ConfigMap("registry-config") {
+ metadata+: app.metadata("registry-config"),
+ data: {
+ "config.yml": std.manifestYamlDoc({
+ version: "0.1",
+ log: {
+ fields: {
+ service: "registry",
+ },
+ },
+ storage: {
+ cache: {
+ blobdescriptor: "inmemory",
+ },
+ filesystem: {
+ rootdirectory: "/var/lib/registry",
+ },
+ },
+ http: {
+ addr: ":5000",
+ headers: {
+ "X-Content-Type-Options": ["nosniff"],
+ },
+ tls: {
+ certificate: "/certs/tls.crt",
+ key: "/certs/tls.key",
+ },
+ },
+ health: {
+ storagedriver: {
+ enabled: true,
+ interval: "10s",
+ threshold: 3,
+ },
+ },
+ auth: {
+ token: {
+ realm: "https://registry.%s/auth" % [cfg.domain],
+ service: "my.docker.registry",
+ issuer: "registry.%s auth server" % [cfg.domain],
+ rootcertbundle: "/authcerts/tls.crt",
+ },
+ },
+ }),
+ },
+ },
+
+ authConfig: kube.ConfigMap("auth-config") {
+ metadata+: app.metadata("auth-config"),
+ data: {
+ "auth_config.yml": std.manifestYamlDoc({
+ server: {
+ addr: ":5001",
+ certificate: "/certs/tls.crt",
+ key: "/certs/tls.key",
+ },
+ token: {
+ issuer: "registry.%s auth server" % [cfg.domain],
+ expiration: 900,
+ },
+ users: {
+ # Password is specified as a BCrypt hash. Use `htpasswd -nB USERNAME` to generate.
+ "admin": {
+ password: "$2y$05$LO.vzwpWC5LZGqThvEfznu8qhb5SGqvBSWY1J3yZ4AxtMRZ3kN5jC", # badmin
+ },
+ "test": {
+ password: "$2y$05$WuwBasGDAgr.QCbGIjKJaep4dhxeai9gNZdmBnQXqpKly57oNutya", # 123
+ },
+ },
+ acl: [
+ {
+ match: {account: "admin"},
+ actions: ["*"],
+ comment: "Admin has full access to everything.",
+ },
+ {
+ match: {account: "user"},
+ actions: ["pull"],
+ comment: "User \"user\" can pull stuff.",
+ },
+ ],
+ }),
+ }
+ },
+
+ authDeployment: kube.Deployment("auth") {
+ metadata+: app.metadata("auth"),
+ spec+: {
+ replicas: 1,
+ template+: {
+ spec+: {
+ volumes_: {
+ config: kube.ConfigMapVolume(app.authConfig),
+ certs: {
+ secret: { secretName: app.authCertificate.spec.secretName },
+ },
+ },
+ containers_: {
+ auth: kube.Container("auth") {
+ image: "cesanta/docker_auth:1",
+ volumeMounts_: {
+ config: { mountPath: "/config" },
+ certs: { mountPath: "/certs" },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ authService: kube.Service("auth") {
+ metadata+: app.metadata("auth"),
+ target_pod:: app.authDeployment.spec.template,
+ spec+: {
+ type: "ClusterIP",
+ ports: [
+ { name: "auth", port: 5001, targetPort: 5001, protocol: "TCP" },
+ ],
+ }
+ },
+ registryDeployment: kube.Deployment("docker-registry") {
+ metadata+: app.metadata("docker-registry"),
+ spec+: {
+ replicas: 1,
+ template+: {
+ spec+: {
+ volumes_: {
+ config: kube.ConfigMapVolume(app.registryConfig),
+ certs: {
+ secret: { secretName: app.registryCertificate.spec.secretName },
+ },
+ authcerts: {
+ secret: { secretName: app.authCertificate.spec.secretName },
+ },
+ },
+ containers_: {
+ registry: kube.Container("docker-registry") {
+ image: "registry:2",
+ args: ["/config/config.yml"],
+ volumeMounts_: {
+ config: { mountPath: "/config" },
+ certs: { mountPath: "/certs" },
+ authcerts: { mountPath: "/authcerts" },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ registryService: kube.Service("docker-registry") {
+ metadata+: app.metadata("docker-registry"),
+ target_pod:: app.registryDeployment.spec.template,
+ spec+: {
+ type: "ClusterIP",
+ ports: [
+ { name: "registry", port: 5000, targetPort: 5000, protocol: "TCP" },
+ ],
+ }
+ },
+ registryIngress: kube.Ingress("registry") {
+ metadata+: app.metadata("registry") {
+ annotations+: {
+ "kubernetes.io/tls-acme": "true",
+ "certmanager.k8s.io/cluster-issuer": "letsencrypt-prod",
+ "nginx.ingress.kubernetes.io/backend-protocol": "HTTPS",
+ },
+ },
+ spec+: {
+ tls: [
+ {
+ hosts: ["registry.%s" % [cfg.domain]],
+ secretName: "registry-tls",
+ },
+ ],
+ rules: [
+ {
+ host: "registry.%s" % [cfg.domain],
+ http: {
+ paths: [
+ { path: "/auth", backend: app.authService.name_port },
+ { path: "/", backend: app.registryService.name_port },
+ ]
+ },
+ }
+ ],
+ },
+ },
+}