Add support for zuul-registry
Change-Id: Ie206f8f7c48da3cfaabb33d16f2a339b35db4e5e
This commit is contained in:
parent
6e0fb7fe1b
commit
d87ea64c06
@ -13,8 +13,6 @@ spec:
|
|||||||
scheduler:
|
scheduler:
|
||||||
config:
|
config:
|
||||||
secretName: zuul-yaml-conf
|
secretName: zuul-yaml-conf
|
||||||
registry:
|
|
||||||
count: 1
|
|
||||||
launcher:
|
launcher:
|
||||||
config:
|
config:
|
||||||
secretName: nodepool-yaml-conf
|
secretName: nodepool-yaml-conf
|
||||||
|
@ -192,6 +192,33 @@ static HTML/Javascript sites). If you enable this, the operator will
|
|||||||
configure a ``zuul-preview`` service to which you may route an Ingress
|
configure a ``zuul-preview`` service to which you may route an Ingress
|
||||||
or LoadBalancer.
|
or LoadBalancer.
|
||||||
|
|
||||||
|
Zuul Registry
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The operator has optional support for deploying a zuul-registry
|
||||||
|
service. This is an experimental add-on for Zuul to act as an
|
||||||
|
intermediate registry for the container image jobs in `zuul-jobs`.
|
||||||
|
|
||||||
|
If you enable this, the operator will, by default, configure a
|
||||||
|
``zuul-registry`` service in a manner appropriate for access from
|
||||||
|
within the cluster only. If you need to access the registry from
|
||||||
|
outside the cluster, you will need to additionally add an Ingress or
|
||||||
|
LoadBalancer, as well as provide TLS certs with the appropriate
|
||||||
|
hostname. Currently, zuul-registry performs its own TLS termination.
|
||||||
|
|
||||||
|
If you usue this, you will also need to provide a ``registry.yaml``
|
||||||
|
config file in a secret. You only need to provide the ``users`` and,
|
||||||
|
if you are accessing the registry outside the cluster, the
|
||||||
|
``public-url`` setting (omit it if you are accessing it from within
|
||||||
|
the cluster only).
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
registry:
|
||||||
|
users:
|
||||||
|
- name: testuser
|
||||||
|
pass: testpass
|
||||||
|
access: write
|
||||||
|
|
||||||
Specification Reference
|
Specification Reference
|
||||||
-----------------------
|
-----------------------
|
||||||
@ -481,3 +508,36 @@ verbatim):
|
|||||||
:default: 0
|
:default: 0
|
||||||
|
|
||||||
How many Zuul Preview servers to manage.
|
How many Zuul Preview servers to manage.
|
||||||
|
|
||||||
|
.. attr:: registry
|
||||||
|
|
||||||
|
.. attr:: count
|
||||||
|
:default: 0
|
||||||
|
|
||||||
|
How many Zuul Registry servers to manage.
|
||||||
|
|
||||||
|
.. attr:: volumeSize
|
||||||
|
:default: 80Gi
|
||||||
|
|
||||||
|
The requested size of the registry storage volume.
|
||||||
|
|
||||||
|
.. attr:: tls
|
||||||
|
|
||||||
|
.. attr:: secretName
|
||||||
|
|
||||||
|
The name of a secret containing a TLS client certificate
|
||||||
|
and key for Zuul Registry. This should be (or the format
|
||||||
|
should match) a standard Kubernetes TLS secret.
|
||||||
|
|
||||||
|
If you omit this, the operator will create a secret for
|
||||||
|
you.
|
||||||
|
|
||||||
|
.. attr:: config
|
||||||
|
|
||||||
|
.. attr:: secretName
|
||||||
|
|
||||||
|
The name of a secret containing a registry
|
||||||
|
configuration file. The key in the secret should be
|
||||||
|
``registry.yaml``. Only provide the ``users`` and, if
|
||||||
|
exposing the registry outside the cluster, the
|
||||||
|
``public-url`` entries.
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
secretName: nodepool-kube-config
|
secretName: nodepool-kube-config
|
||||||
registry:
|
registry:
|
||||||
count: 1
|
count: 1
|
||||||
|
config:
|
||||||
|
secretName: zuul-registry-conf
|
||||||
preview:
|
preview:
|
||||||
count: 1
|
count: 1
|
||||||
|
|
||||||
@ -45,7 +47,3 @@
|
|||||||
|
|
||||||
- name: Test the cert-manager
|
- name: Test the cert-manager
|
||||||
include_tasks: ./tasks/test_cert_manager.yaml
|
include_tasks: ./tasks/test_cert_manager.yaml
|
||||||
|
|
||||||
# TODO: implement
|
|
||||||
# - name: Test the registry
|
|
||||||
# include_tasks: ./tasks/test_registry.yaml
|
|
||||||
|
@ -68,3 +68,12 @@
|
|||||||
- name: nodepool-kube-config
|
- name: nodepool-kube-config
|
||||||
data:
|
data:
|
||||||
kube.config: "{{ _kube_config.stdout }}"
|
kube.config: "{{ _kube_config.stdout }}"
|
||||||
|
|
||||||
|
- name: zuul-registry-conf
|
||||||
|
data:
|
||||||
|
registry.yaml: |
|
||||||
|
registry:
|
||||||
|
users:
|
||||||
|
- name: testuser
|
||||||
|
pass: testpass
|
||||||
|
access: write
|
||||||
|
@ -1,21 +1,23 @@
|
|||||||
- name: Get registry service ip
|
- k8s:
|
||||||
command: kubectl get svc registry -o "jsonpath={.spec.clusterIP}"
|
namespace: default
|
||||||
register: _registry_ip
|
definition:
|
||||||
|
apiVersion: batch/v1
|
||||||
- name: Add registry to /etc/hosts
|
kind: Job
|
||||||
become: yes
|
metadata:
|
||||||
lineinfile:
|
name: test-registry
|
||||||
path: /etc/hosts
|
spec:
|
||||||
regexp: "^.* registry$"
|
template:
|
||||||
line: "{{ _registry_ip.stdout_lines[0] }} registry"
|
spec:
|
||||||
|
containers:
|
||||||
- name: Get registry password
|
- name: test-registry
|
||||||
command: kubectl get secret zuul-registry-user-rw -o "jsonpath={.data.password}"
|
image: quay.io/containers/podman:latest
|
||||||
register: _registry_password
|
command: ['podman', 'login', '--tls-verify=false', 'https://zuul-registry/', '-u', 'testuser', '-p', 'testpass']
|
||||||
|
securityContext:
|
||||||
- name: Test registry login
|
privileged: true
|
||||||
command: >
|
restartPolicy: Never
|
||||||
podman login
|
backoffLimit: 4
|
||||||
--tls-verify=false registry:9000
|
wait: yes
|
||||||
-u zuul
|
wait_timeout: 300
|
||||||
-p "{{ _registry_password.stdout_lines[0] | b64decode }}"
|
wait_condition:
|
||||||
|
type: Complete
|
||||||
|
status: "True"
|
||||||
|
@ -156,3 +156,6 @@
|
|||||||
|
|
||||||
- name: Test the preview
|
- name: Test the preview
|
||||||
include_tasks: ./tasks/test_preview.yaml
|
include_tasks: ./tasks/test_preview.yaml
|
||||||
|
|
||||||
|
- name: Test the registry
|
||||||
|
include_tasks: ./tasks/test_registry.yaml
|
||||||
|
107
zuul_operator/templates/zuul-registry.yaml
Normal file
107
zuul_operator/templates/zuul-registry.yaml
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
{%- if manage_registry_cert %}
|
||||||
|
---
|
||||||
|
apiVersion: cert-manager.io/v1alpha2
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: zuul-registry-tls
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: zuul
|
||||||
|
app.kubernetes.io/instance: {{ instance_name }}
|
||||||
|
app.kubernetes.io/part-of: zuul
|
||||||
|
app.kubernetes.io/component: zuul-registry-tls
|
||||||
|
spec:
|
||||||
|
keyEncoding: pkcs8
|
||||||
|
secretName: zuul-registry-tls
|
||||||
|
commonName: client
|
||||||
|
usages:
|
||||||
|
- digital signature
|
||||||
|
- key encipherment
|
||||||
|
- server auth
|
||||||
|
- client auth
|
||||||
|
issuerRef:
|
||||||
|
name: ca-issuer
|
||||||
|
kind: Issuer
|
||||||
|
{%- endif %}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: zuul-registry
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: zuul
|
||||||
|
app.kubernetes.io/instance: {{ instance_name }}
|
||||||
|
app.kubernetes.io/part-of: zuul
|
||||||
|
app.kubernetes.io/component: zuul-registry
|
||||||
|
spec:
|
||||||
|
type: NodePort
|
||||||
|
ports:
|
||||||
|
- name: zuul-registry
|
||||||
|
port: 443
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: registry
|
||||||
|
selector:
|
||||||
|
app.kubernetes.io/name: zuul
|
||||||
|
app.kubernetes.io/instance: {{ instance_name }}
|
||||||
|
app.kubernetes.io/part-of: zuul
|
||||||
|
app.kubernetes.io/component: zuul-registry
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: zuul-registry
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: zuul
|
||||||
|
app.kubernetes.io/instance: {{ instance_name }}
|
||||||
|
app.kubernetes.io/part-of: zuul
|
||||||
|
app.kubernetes.io/component: zuul-registry
|
||||||
|
spec:
|
||||||
|
replicas: {{ spec.registry.count }}
|
||||||
|
serviceName: zuul-registry
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: zuul
|
||||||
|
app.kubernetes.io/instance: {{ instance_name }}
|
||||||
|
app.kubernetes.io/part-of: zuul
|
||||||
|
app.kubernetes.io/component: zuul-registry
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: zuul
|
||||||
|
app.kubernetes.io/instance: {{ instance_name }}
|
||||||
|
app.kubernetes.io/part-of: zuul
|
||||||
|
app.kubernetes.io/component: zuul-registry
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: registry
|
||||||
|
image: {{ spec.imagePrefix }}/zuul-registry:{{ spec.zuulImageVersion }}
|
||||||
|
env:
|
||||||
|
- name: DEBUG
|
||||||
|
value: '1'
|
||||||
|
ports:
|
||||||
|
- name: registry
|
||||||
|
containerPort: 9000
|
||||||
|
volumeMounts:
|
||||||
|
- name: zuul-registry-config
|
||||||
|
mountPath: /conf
|
||||||
|
readOnly: true
|
||||||
|
- name: zuul-registry-tls
|
||||||
|
mountPath: /tls
|
||||||
|
readOnly: true
|
||||||
|
- name: zuul-registry
|
||||||
|
mountPath: /storage
|
||||||
|
volumes:
|
||||||
|
- name: zuul-registry-config
|
||||||
|
secret:
|
||||||
|
secretName: zuul-registry-generated-config
|
||||||
|
- name: zuul-registry-tls
|
||||||
|
secret:
|
||||||
|
secretName: {{ spec.registry.tls.secretName }}
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: zuul-registry
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ spec.registry.volumeSize }} #80Gi
|
@ -12,6 +12,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import kopf
|
||||||
import copy
|
import copy
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
@ -72,10 +73,17 @@ class Zuul:
|
|||||||
self.spec.setdefault('web', {}).setdefault('count', 1)
|
self.spec.setdefault('web', {}).setdefault('count', 1)
|
||||||
self.spec.setdefault('fingergw', {}).setdefault('count', 1)
|
self.spec.setdefault('fingergw', {}).setdefault('count', 1)
|
||||||
self.spec.setdefault('preview', {}).setdefault('count', 0)
|
self.spec.setdefault('preview', {}).setdefault('count', 0)
|
||||||
|
registry = self.spec.setdefault('registry', {})
|
||||||
|
registry.setdefault('count', 0)
|
||||||
|
registry.setdefault('volumeSize', '80Gi')
|
||||||
|
registry_tls = registry.setdefault('tls', {})
|
||||||
|
self.manage_registry_cert = ('secretName' not in registry_tls)
|
||||||
|
registry_tls.setdefault('secretName', 'zuul-registry-tls')
|
||||||
|
|
||||||
self.spec.setdefault('imagePrefix', 'docker.io/zuul')
|
self.spec.setdefault('imagePrefix', 'docker.io/zuul')
|
||||||
self.spec.setdefault('zuulImageVersion', 'latest')
|
self.spec.setdefault('zuulImageVersion', 'latest')
|
||||||
self.spec.setdefault('zuulPreviewImageVersion', 'latest')
|
self.spec.setdefault('zuulPreviewImageVersion', 'latest')
|
||||||
|
self.spec.setdefault('zuulRegistryImageVersion', 'latest')
|
||||||
self.spec.setdefault('nodepoolImageVersion', 'latest')
|
self.spec.setdefault('nodepoolImageVersion', 'latest')
|
||||||
|
|
||||||
self.cert_manager = certmanager.CertManager(
|
self.cert_manager = certmanager.CertManager(
|
||||||
@ -314,7 +322,55 @@ class Zuul:
|
|||||||
except pykube.exceptions.ObjectDoesNotExist:
|
except pykube.exceptions.ObjectDoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def write_registry_conf(self):
|
||||||
|
config_secret = self.spec['registry'].get('config', {}).get('secretName')
|
||||||
|
if not config_secret:
|
||||||
|
raise kopf.PermanentError("No registry config secret found")
|
||||||
|
|
||||||
|
try:
|
||||||
|
obj = objects.Secret.objects(self.api).\
|
||||||
|
filter(namespace=self.namespace).\
|
||||||
|
get(name=config_secret)
|
||||||
|
except pykube.exceptions.ObjectDoesNotExist:
|
||||||
|
raise kopf.TemporaryError("Registry config secret not found")
|
||||||
|
|
||||||
|
# Shard the config so we can create a deployment + secret for
|
||||||
|
# each provider.
|
||||||
|
registry_yaml = yaml.safe_load(base64.b64decode(
|
||||||
|
obj.obj['data']['registry.yaml']))
|
||||||
|
|
||||||
|
reg = registry_yaml['registry']
|
||||||
|
if 'public-url' not in reg:
|
||||||
|
reg['public-url'] = 'https://zuul-registry'
|
||||||
|
reg['address'] = '0.0.0.0'
|
||||||
|
reg['port'] = 9000
|
||||||
|
reg['tls-cert'] = '/tls/tls.crt'
|
||||||
|
reg['tls-key'] = '/tls/tls.key'
|
||||||
|
reg['secret'] = utils.generate_password(56)
|
||||||
|
reg['storage'] = {
|
||||||
|
'driver': 'filesystem',
|
||||||
|
'root': '/storage',
|
||||||
|
}
|
||||||
|
|
||||||
|
text = yaml.dump(registry_yaml)
|
||||||
|
utils.update_secret(self.api, self.namespace,
|
||||||
|
'zuul-registry-generated-config',
|
||||||
|
string_data={'registry.yaml': text})
|
||||||
|
|
||||||
|
def create_registry(self):
|
||||||
|
self.write_registry_conf()
|
||||||
|
kw = {
|
||||||
|
'instance_name': self.name,
|
||||||
|
'spec': self.spec,
|
||||||
|
'manage_registry_cert': self.manage_registry_cert,
|
||||||
|
}
|
||||||
|
utils.apply_file(self.api, 'zuul-registry.yaml',
|
||||||
|
namespace=self.namespace, **kw)
|
||||||
|
|
||||||
def create_zuul(self):
|
def create_zuul(self):
|
||||||
|
if self.spec['registry']['count']:
|
||||||
|
self.create_registry()
|
||||||
|
|
||||||
kw = {
|
kw = {
|
||||||
'zuul_conf_sha': self.zuul_conf_sha,
|
'zuul_conf_sha': self.zuul_conf_sha,
|
||||||
'zuul_tenant_secret': self.tenant_secret,
|
'zuul_tenant_secret': self.tenant_secret,
|
||||||
|
Loading…
Reference in New Issue
Block a user