Add quay-kubernetes package / Add quay CD to k8s
This commit is contained in:
parent
2f750bfc87
commit
1d0313229e
45 changed files with 1129 additions and 10 deletions
1
deploy/quay-app/.apprignore
Normal file
1
deploy/quay-app/.apprignore
Normal file
|
@ -0,0 +1 @@
|
|||
stack/
|
8
deploy/quay-app/Chart.jsonnet
Normal file
8
deploy/quay-app/Chart.jsonnet
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
name: 'quay/quay-app',
|
||||
author: 'Antoine Legrand',
|
||||
version: std.split(importstr "VERSION", "\n")[0],
|
||||
description: 'quay',
|
||||
license: 'MIT',
|
||||
expander: 'jinja2'
|
||||
}
|
9
deploy/quay-app/README.md
Normal file
9
deploy/quay-app/README.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Configure
|
||||
##
|
||||
- The package reads automatically ./stack/* and use every files there in configuration.
|
||||
- if a `./stack/config.yaml` exists, the file is merged with the variable `config`.
|
||||
Config precedence order:
|
||||
1. Default defined in the package level
|
||||
2. file content in `stack/*`
|
||||
3. value variables.stack_files
|
||||
Except for `config.yaml`, precedence is a strict replacement, for config.yaml is a mergePatch.
|
16
deploy/quay-app/lib/quay.libsonnet
Normal file
16
deploy/quay-app/lib/quay.libsonnet
Normal file
|
@ -0,0 +1,16 @@
|
|||
local appr = import 'appr.libsonnet';
|
||||
|
||||
{
|
||||
# Read all files in a directory
|
||||
# @todo(ant31): replace walk by listdir
|
||||
load_stack_files(path):: (
|
||||
if appr.path_exists(path)
|
||||
then {[appr.path.basename(file)]: appr.readfile(file, encode=true) for file in appr.walkdir(path)}
|
||||
else {}
|
||||
),
|
||||
|
||||
# Create a patch to add/update annotation with a rand value.
|
||||
# Use to force a Deployment rolling-update
|
||||
rand_label():: {metadata+: {annotations+: {'resource.appr/rand': appr.randAlphaNum()}}},
|
||||
|
||||
}
|
155
deploy/quay-app/manifest.jsonnet
Normal file
155
deploy/quay-app/manifest.jsonnet
Normal file
|
@ -0,0 +1,155 @@
|
|||
local appr = import 'appr.libsonnet';
|
||||
local quaylib = import 'lib/quay.libsonnet';
|
||||
|
||||
function(
|
||||
params={}
|
||||
)
|
||||
|
||||
|
||||
appr.package({
|
||||
package: import "Chart.jsonnet",
|
||||
|
||||
variables: {
|
||||
namespace: 'default',
|
||||
cluster_domain_name: 'cluster.local',
|
||||
|
||||
# Minimum configuration
|
||||
base_config: (import "templates/conf/config.libsonnet")($.variables),
|
||||
|
||||
# Additional values stack/config.yaml values
|
||||
config: {},
|
||||
|
||||
# path to the local stack configuration directory
|
||||
stack_path: "stack",
|
||||
|
||||
# load local `stack` directory if exists
|
||||
stack_files: {
|
||||
"syslog-ng-extra.conf": appr.b64encode(importstr "templates/conf/syslog-ng-extra.conf")} +
|
||||
if $.variables.license != null then {"license": appr.b64encode($.variables.license) } else {} +
|
||||
quaylib.load_stack_files($.variables.stack_path),
|
||||
|
||||
# load license
|
||||
license: null,
|
||||
|
||||
# Image tag and repo
|
||||
tag: $.package.version,
|
||||
image: 'quay.io/quay/quay:%s' % self.tag,
|
||||
|
||||
# Used in the pull secret
|
||||
docker_user: 'changeme',
|
||||
docker_pass: 'changeme',
|
||||
|
||||
# Redis configuration
|
||||
redis_host: 'quay-redis.%s.svc.%s:6379' % [$.variables.namespace, $.variables.cluster_domain_name],
|
||||
redisconf: {redis_parts:: std.split($.variables.redis_host, ":"),
|
||||
"host": self.redis_parts[0], port: self.redis_parts[1]},
|
||||
|
||||
# Configure the ingress with the ingress controller class and domain to use
|
||||
domain: 'quay.%s.example.com' % $.variables.namespace,
|
||||
ingress: {
|
||||
class: 'nginx',
|
||||
tls: "kubernetes.io/tls-acme",
|
||||
domains: std.split($.variables.domain, ','),
|
||||
annotations: {}
|
||||
},
|
||||
|
||||
# Force to reload the secret/configuration
|
||||
reconfigure: "false",
|
||||
|
||||
# Deploy a postgres (don't use it for prod)
|
||||
deploy_db: 'false',
|
||||
|
||||
# Postgres deployment configuratio
|
||||
db: {
|
||||
user: 'quay',
|
||||
password: 'quay',
|
||||
name: 'quay',
|
||||
},
|
||||
|
||||
# Quay DB_URI
|
||||
db_uri: 'postgresql://%s:%s@postgres.%s.svc.%s/%s' % [$.variables.db.user,
|
||||
$.variables.db.password,
|
||||
$.variables.namespace,
|
||||
$.variables.cluster_domain_name,
|
||||
$.variables.db.name],
|
||||
|
||||
},
|
||||
|
||||
|
||||
# ServiceAccount to attach Rbac rules
|
||||
resources: appr.compact([ # + appr.importResourceDir('templates/')
|
||||
{
|
||||
value: {apiVersion: 'v1', kind: 'ServiceAccount',
|
||||
metadata: {name: 'quay-enterprise'}}
|
||||
},
|
||||
|
||||
# Grant secret read/write permission inside the namespace
|
||||
{
|
||||
value: (import 'templates/quay-enterprise-role.libsonnet')($.variables),
|
||||
},
|
||||
|
||||
# Bind role to the Service account
|
||||
{
|
||||
value: (import 'templates/quay-enterprise-rolebinding.libsonnet')($.variables),
|
||||
},
|
||||
|
||||
# Quay.io robot / user account. Protected from default values
|
||||
{
|
||||
value: (import 'templates/quay-enterprise-pullsecret.libsonnet')($.variables),
|
||||
protected: if $.variables.docker_user == "changeme" || $.variables.docker_pass == "changeme"
|
||||
then true else false
|
||||
},
|
||||
|
||||
# Quay configuration files (quay/conf/stack), automatically read local the "./stack" directory to load values.
|
||||
# Values can also be loaded from $.variables.stack_files
|
||||
# Protected unless explicitly requested (reconfigure == "true").
|
||||
{
|
||||
value: (import 'templates/quay-enterprise-secret.libsonnet')($.variables),
|
||||
protected: if $.variables.reconfigure == "true" then false else true
|
||||
},
|
||||
|
||||
# Quay-registry deployment
|
||||
# Force a rollout when the secret is reconfigured by updating a label (see randLabel)
|
||||
{
|
||||
value: appr.loadObject(appr.jinja2(importstr 'templates/quay-enterprise-app-dp.yaml', $.variables)) +
|
||||
if $.variables.reconfigure == "true" then
|
||||
# trigger a rollout
|
||||
quaylib.rand_label()
|
||||
else {}
|
||||
}, # + {value+: if $.variables.reconfigure == "true" then randLabel() else {},},
|
||||
|
||||
{
|
||||
template: (importstr 'templates/quay-enterprise-service.yaml'),
|
||||
},
|
||||
|
||||
# Redis
|
||||
{
|
||||
template: (importstr 'templates/quay-enterprise-redis-service.yaml'),
|
||||
},
|
||||
|
||||
{
|
||||
template: (importstr 'templates/quay-enterprise-redis.yaml'),
|
||||
},
|
||||
|
||||
|
||||
# Ingress, assumes usage of kube-lego and an ingress controller.
|
||||
# see variables.ingress for configuration
|
||||
{
|
||||
value: (import 'templates/quay-enterprise-ingress.libsonnet')($.variables.ingress),
|
||||
},
|
||||
|
||||
|
||||
]),
|
||||
|
||||
|
||||
deploy: appr.compact([
|
||||
if $.variables.deploy_db == 'true' then
|
||||
{name: 'quay/postgres-app',
|
||||
variables: {
|
||||
user: $.variables.db.user,
|
||||
dbname: $.variables.db.name,
|
||||
password: $.variables.db.password
|
||||
}},
|
||||
{name: '$self'},
|
||||
]),
|
||||
}, params)
|
53
deploy/quay-app/templates/conf/config.libsonnet
Normal file
53
deploy/quay-app/templates/conf/config.libsonnet
Normal file
|
@ -0,0 +1,53 @@
|
|||
function(vars)
|
||||
{
|
||||
BUILDLOGS_REDIS: vars.redisconf,
|
||||
USER_EVENTS_REDIS: vars.redisconf,
|
||||
DB_URI: vars.db_uri,
|
||||
SETUP_COMPLETE: true,
|
||||
# Not deployed, features forced turn off
|
||||
FEATURE_SECURITY_SCANNER: false,
|
||||
FEATURE_BUILD_SUPPORT: false,
|
||||
FEATURE_ACI_CONVERSION: false,
|
||||
FEATURE_GITHUB_BUILD: false,
|
||||
FEATURE_BITBUCKET_BUILD: false,
|
||||
FEATURE_GITLAB_BUILD: false,
|
||||
GITHUB_TRIGGER_CONFIG: null,
|
||||
GITLAB_TRIGGER_KIND: {},
|
||||
AUTHENTICATION_TYPE: "Database",
|
||||
PREFERRED_URL_SCHEME: "https",
|
||||
SERVER_HOSTNAME: vars.ingress.domains[0],
|
||||
EXTERNAL_TLS_TERMINATION: true,
|
||||
INSTANCE_SERVICE_KEY_KID_LOCATION: 'conf/quay.kid',
|
||||
INSTANCE_SERVICE_KEY_LOCATION: 'conf/quay.pem',
|
||||
}
|
||||
|
||||
# local s3_storage = { local_us: ["S3Storage",
|
||||
# {storage_path: "",
|
||||
# s3_access_key: vars.storage.s3.access_key,
|
||||
# s3_secret_key: vars.storage.s3.secret_key,
|
||||
# s3_bucket: vars.storage.s3.bucket},
|
||||
# ]
|
||||
# };
|
||||
|
||||
# extra: {
|
||||
# REGISTRY_TITLE: "Quay (%s)" % vars.ingress.host,
|
||||
# REGISTRY_TITLE_SHORT: "Quay (%s)" % vars.ingress.host,
|
||||
# TESTING: true,
|
||||
# DEBUGGING: true,
|
||||
# USE_CDN: false,
|
||||
# FEATURE_ANONYMOUS_ACCESS: true,
|
||||
# FEATURE_MAILING: false,
|
||||
# AUTHENTICATION_TYPE: "Database",
|
||||
# ENTERPRISE_LOGO_URL: "/static/img/quay-logo.png",
|
||||
# LOG_ARCHIVE_LOCATION: "default",
|
||||
# TAG_EXPIRATION_OPTIONS: ["2d"],
|
||||
# DISTRIBUTED_STORAGE_CONFIG: {
|
||||
# default: [
|
||||
# "LocalStorage",
|
||||
# {storage_path: "/datastorage/registry"}]},
|
||||
# DISTRIBUTED_STORAGE_DEFAULT_LOCATIONS: [],
|
||||
# DISTRIBUTED_STORAGE_PREFERENCE: ["default"],
|
||||
# USERFILES_LOCATION: "default",
|
||||
# USERFILES_PATH: "userfiles/",
|
||||
# }
|
||||
# }
|
7
deploy/quay-app/templates/conf/syslog-ng-extra.conf
Normal file
7
deploy/quay-app/templates/conf/syslog-ng-extra.conf
Normal file
|
@ -0,0 +1,7 @@
|
|||
destination d_stdout {
|
||||
pipe("/dev/stdout");
|
||||
};
|
||||
|
||||
log {
|
||||
source(s_src); destination(d_stdout);
|
||||
};
|
37
deploy/quay-app/templates/quay-dev-initdb-job.yaml
Normal file
37
deploy/quay-app/templates/quay-dev-initdb-job.yaml
Normal file
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: quay-dev-initdb
|
||||
spec:
|
||||
activeDeadlineSeconds: 100
|
||||
template:
|
||||
metadata:
|
||||
name: quay-dev-initdb
|
||||
spec:
|
||||
containers:
|
||||
- name: quay
|
||||
image: quay.io/quay/quay-ci:master
|
||||
env:
|
||||
- name: TEST_DATABASE_URI
|
||||
value: "postgres://"
|
||||
- name: SKIP_DB_SCHEMA
|
||||
value: "true"
|
||||
command:
|
||||
- venv/bin/python
|
||||
- initdb.py
|
||||
volumeMounts:
|
||||
- name: configvolume
|
||||
readOnly: false
|
||||
mountPath: /conf/stack
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 500Mi
|
||||
imagePullSecrets:
|
||||
- name: coreos-pull-secret
|
||||
volumes:
|
||||
- name: configvolume
|
||||
secret:
|
||||
secretName: quay-enterprise-config-secret
|
||||
restartPolicy: Never
|
55
deploy/quay-app/templates/quay-enterprise-app-dp.yaml
Normal file
55
deploy/quay-app/templates/quay-enterprise-app-dp.yaml
Normal file
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
namespace: quay-enterprise
|
||||
name: quay-enterprise-app
|
||||
labels:
|
||||
quay-enterprise-component: app
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
quay-enterprise-component: app
|
||||
spec:
|
||||
serviceAccountName: "quay-enterprise"
|
||||
containers:
|
||||
- name: quay-enterprise-app
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /status
|
||||
port: 80
|
||||
initialDelaySeconds: 300
|
||||
periodSeconds: 30
|
||||
failureThreshold: 3
|
||||
successThreshold: 1
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /status
|
||||
port: 80
|
||||
initialDelaySeconds: 45
|
||||
failureThreshold: 6
|
||||
periodSeconds: 20
|
||||
env:
|
||||
- name: QE_K8S_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
image: {{image}}
|
||||
ports:
|
||||
- containerPort: 80
|
||||
volumeMounts:
|
||||
- name: configvolume
|
||||
readOnly: false
|
||||
mountPath: /conf/stack
|
||||
resources:
|
||||
limits:
|
||||
cpu: 1
|
||||
memory: 2Gi
|
||||
imagePullSecrets:
|
||||
- name: coreos-pull-secret
|
||||
volumes:
|
||||
- name: configvolume
|
||||
secret:
|
||||
secretName: quay-enterprise-config-secret
|
31
deploy/quay-app/templates/quay-enterprise-ingress.libsonnet
Normal file
31
deploy/quay-app/templates/quay-enterprise-ingress.libsonnet
Normal file
|
@ -0,0 +1,31 @@
|
|||
function(ingress={ class: 'none', tls: "true", domains: ['quay.example.com'] })
|
||||
|
||||
{
|
||||
apiVersion: "extensions/v1beta1",
|
||||
kind: "Ingress",
|
||||
metadata: {
|
||||
annotations: {
|
||||
"kubernetes.io/ingress.class": ingress.class,
|
||||
[if std.type(ingress.tls) == "string" then ingress.tls]: "true"} +
|
||||
if std.objectHas(ingress, "annotations") then ingress.annotations else {},
|
||||
name: "quay-enterprise",
|
||||
},
|
||||
|
||||
spec: {
|
||||
rules: [{
|
||||
host: domain,
|
||||
http: {
|
||||
paths: [{
|
||||
backend: {
|
||||
serviceName: "quay-enterprise",
|
||||
servicePort: 80,},
|
||||
path: "/"}]},
|
||||
} for domain in ingress.domains],
|
||||
} +
|
||||
|
||||
if std.type(ingress.tls) == "string" then
|
||||
{tls: [{
|
||||
hosts: ingress.domains,
|
||||
secretName: "quay-enterprise-tls",
|
||||
}]} else {},
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
local appr = import "appr.libsonnet";
|
||||
function(variables={})
|
||||
{
|
||||
local docker_login = [variables.docker_user, variables.docker_pass],
|
||||
data: {
|
||||
".dockercfg": appr.b64encode('{"quay.io": {"username": "%s", "password": "%s","email":"toto@toto.com","auth": "%s"}}' % (docker_login + [appr.b64encode("%s:%s" % docker_login)])),
|
||||
},
|
||||
kind: "Secret",
|
||||
metadata: {
|
||||
name: "coreos-pull-secret",
|
||||
},
|
||||
|
||||
type: "kubernetes.io/dockercfg"
|
||||
}
|
13
deploy/quay-app/templates/quay-enterprise-redis-service.yaml
Normal file
13
deploy/quay-app/templates/quay-enterprise-redis-service.yaml
Normal file
|
@ -0,0 +1,13 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
namespace: quay-redis
|
||||
name: quay-redis
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 6379
|
||||
targetPort: 6379
|
||||
selector:
|
||||
quay-enterprise-component: redis
|
24
deploy/quay-app/templates/quay-enterprise-redis.yaml
Normal file
24
deploy/quay-app/templates/quay-enterprise-redis.yaml
Normal file
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
namespace: quay-enterprise
|
||||
name: quay-enterprise-redis
|
||||
labels:
|
||||
quay-enterprise-component: redis
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
quay-enterprise-component: redis
|
||||
spec:
|
||||
containers:
|
||||
- name: redis-master
|
||||
image: quay.io/quay/redis
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 500Mi
|
21
deploy/quay-app/templates/quay-enterprise-role.libsonnet
Normal file
21
deploy/quay-app/templates/quay-enterprise-role.libsonnet
Normal file
|
@ -0,0 +1,21 @@
|
|||
local appr = import "appr.libsonnet";
|
||||
function(vars={})
|
||||
{
|
||||
kind: "Role",
|
||||
apiVersion: 'rbac.authorization.k8s.io/v1beta1',
|
||||
metadata: {
|
||||
name: "quay-enterprise",
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
apiGroups: [""],
|
||||
resources: ["secrets"],
|
||||
verbs: ["get", "update", "patch"],
|
||||
},
|
||||
{
|
||||
apiGroups: [""],
|
||||
resources: ["namespaces"],
|
||||
verbs: ["get"],
|
||||
},
|
||||
],
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
function(vars={})
|
||||
{
|
||||
apiVersion: "rbac.authorization.k8s.io/v1beta1",
|
||||
kind: "RoleBinding",
|
||||
metadata: {
|
||||
name: "quay-enterprise-binding",
|
||||
namespace: vars.namespace,
|
||||
},
|
||||
roleRef: {
|
||||
apiGroup: "rbac.authorization.k8s.io",
|
||||
kind: "Role",
|
||||
name: "quay-enterprise",
|
||||
},
|
||||
subjects: [
|
||||
{
|
||||
kind: "ServiceAccount",
|
||||
name: "quay-enterprise",
|
||||
namespace: vars.namespace,
|
||||
}
|
||||
]
|
||||
}
|
34
deploy/quay-app/templates/quay-enterprise-secret.libsonnet
Normal file
34
deploy/quay-app/templates/quay-enterprise-secret.libsonnet
Normal file
|
@ -0,0 +1,34 @@
|
|||
local appr = import "appr.libsonnet";
|
||||
local b64e = appr.b64decode;
|
||||
|
||||
function(vars={})
|
||||
|
||||
# Deserialize config.yaml if exists
|
||||
local local_stack_config = (
|
||||
local confpath = "config.yaml";
|
||||
if std.objectHasAll(vars.stack_files, confpath)
|
||||
then appr.loadObject(appr.b64decode(vars.stack_files[confpath]))
|
||||
else {}
|
||||
);
|
||||
|
||||
# Merge all config together
|
||||
# Precedence: package-config (vars.config) < local stack/config.yaml < base-config (vars.base-config)
|
||||
local config_yaml = {'config.yaml': appr.b64encode(appr.to_yaml(
|
||||
vars.config +
|
||||
local_stack_config +
|
||||
vars.base_config))};
|
||||
|
||||
# Merge stack files
|
||||
local stack_files = vars.stack_files + config_yaml;
|
||||
|
||||
{
|
||||
apiVersion: "v1",
|
||||
kind: "Secret",
|
||||
metadata: {
|
||||
namespace: "quay-enterprise",
|
||||
name: "quay-enterprise-config-secret"},
|
||||
|
||||
# base64 encode all files
|
||||
data: { [file]: stack_files[file]
|
||||
for file in std.objectFields(stack_files) if stack_files[file] != null}
|
||||
}
|
13
deploy/quay-app/templates/quay-enterprise-service.yaml
Normal file
13
deploy/quay-app/templates/quay-enterprise-service.yaml
Normal file
|
@ -0,0 +1,13 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
namespace: quay-enterprise
|
||||
name: quay-enterprise
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 80
|
||||
selector:
|
||||
quay-enterprise-component: app
|
Reference in a new issue