From 10f04d7273901b3fe705e0c6509555bba8a78ef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Mass=C3=A9?= Date: Tue, 26 May 2026 18:59:00 +0000 Subject: [PATCH] add cookbook for quay --- cookbooks/quay/Makefile | 12 + .../quay/config/examples/app/config.yaml | 327 ++++++++++++++++++ .../quay/config/examples/clair/config.yaml | 31 ++ .../quay/config/examples/redis/redis.conf | 10 + .../quay/config/examples/redis/redis.env | 1 + cookbooks/quay/config/quay_load_tls_certs.sh | 14 + cookbooks/quay/other/postgresql/clair.sql | 4 + cookbooks/quay/other/postgresql/quay.sh | 32 ++ cookbooks/quay/overlay.bu | 9 + cookbooks/quay/quay-app.container | 56 +++ cookbooks/quay/quay-app.image | 6 + cookbooks/quay/quay-clair.container | 44 +++ cookbooks/quay/quay-clair.image | 6 + cookbooks/quay/quay-init-certificate.service | 15 + .../quay-load-renewed-certificate.service | 17 + cookbooks/quay/quay-redis.container | 49 +++ cookbooks/quay/quay-redis.image | 5 + cookbooks/quay/quay.target | 13 + cookbooks/quay/tmpfiles.d/quay.conf | 7 + 19 files changed, 658 insertions(+) create mode 100644 cookbooks/quay/Makefile create mode 100644 cookbooks/quay/config/examples/app/config.yaml create mode 100644 cookbooks/quay/config/examples/clair/config.yaml create mode 100644 cookbooks/quay/config/examples/redis/redis.conf create mode 100644 cookbooks/quay/config/examples/redis/redis.env create mode 100755 cookbooks/quay/config/quay_load_tls_certs.sh create mode 100644 cookbooks/quay/other/postgresql/clair.sql create mode 100755 cookbooks/quay/other/postgresql/quay.sh create mode 100644 cookbooks/quay/overlay.bu create mode 100644 cookbooks/quay/quay-app.container create mode 100644 cookbooks/quay/quay-app.image create mode 100644 cookbooks/quay/quay-clair.container create mode 100644 cookbooks/quay/quay-clair.image create mode 100644 cookbooks/quay/quay-init-certificate.service create mode 100644 cookbooks/quay/quay-load-renewed-certificate.service create mode 100644 cookbooks/quay/quay-redis.container create mode 100644 cookbooks/quay/quay-redis.image create mode 100644 cookbooks/quay/quay.target create mode 100644 cookbooks/quay/tmpfiles.d/quay.conf diff --git a/cookbooks/quay/Makefile b/cookbooks/quay/Makefile new file mode 100644 index 0000000..5850e0c --- /dev/null +++ b/cookbooks/quay/Makefile @@ -0,0 +1,12 @@ +## +## Makefile for Quay Container Registry quadlet +## + +# Quay quadlet is mapped to the 10026 user (quay) and 10000 group (itix-svc) +PROJECT_UID = 10026 +PROJECT_GID = 10000 + +DEPENDENCIES = postgresql lego + +# Include common Makefile +include ../../scripts/common.mk diff --git a/cookbooks/quay/config/examples/app/config.yaml b/cookbooks/quay/config/examples/app/config.yaml new file mode 100644 index 0000000..4b9c458 --- /dev/null +++ b/cookbooks/quay/config/examples/app/config.yaml @@ -0,0 +1,327 @@ +# Quay Container Registry configuration +# Copy this file to /etc/quadlets/quay/app/config.yaml and customize it. +# +# For more information on configuration options, see: +# - the json schema of the config tool: https://github.com/quay/app/blob/master/config-tool/utils/generate/schema.json +# - the json schema of the Python core: https://github.com/quay/app/blob/master/util/config/schema.py + +# The URL at which Quay is accessible, without the scheme. +SERVER_HOSTNAME: localhost + +# The URL scheme to use when hitting Quay. If Quay is behind SSL *at all*, this *must* be `https` +PREFERRED_URL_SCHEME: https + +# SSL certificates for HTTPS. +SSL_CERTFILE: /quay-registry/conf/stack/tls/ssl.crt +SSL_KEYFILE: /quay-registry/conf/stack/tls/ssl.key + +# Secret key for signing database entries (generate a strong random value) +DATABASE_SECRET_KEY: 'REDACTEDREDACTEDREDACTED' + +# Local filesystem storage for container images +DISTRIBUTED_STORAGE_CONFIG: + default: + - LocalStorage + - storage_path: /datastorage/registry +DISTRIBUTED_STORAGE_DEFAULT_LOCATIONS: [] +DISTRIBUTED_STORAGE_PREFERENCE: + - default + +# The authentication engine to use for credential authentication. +AUTHENTICATION_TYPE: Database + +# The URI at which to access the database, including any credentials. +DB_URI: postgresql://quay:quay@127.0.0.1:5432/quay + +# If specified, connection arguments for the database such as timeouts and SSL. +# DB_CONNECTION_ARGS: + +# Connection information for Redis for build logs caching +BUILDLOGS_REDIS: + host: localhost + password: quay + port: 6379 + +# Connection information for Redis for user events caching +USER_EVENTS_REDIS: + host: localhost + password: quay + port: 6379 + +# Whether to allow the first user to be bootstrapped through API call. +# If true, the first call to the /api/v1/user/initialize endpoint will create a user with the provided credentials, and this endpoint will be disabled after that. Defaults to False. +# +# Tip: You can then create the first superuser with the following command: +# +# ```sh +# ADMIN_PASSWORD='F00barbaz' +# curl -vk -X POST https://localhost:8443/api/v1/user/initialize -H 'Content-Type: application/json' --data "{\"username\":\"quayadmin\",\"password\":\"${ADMIN_PASSWORD}\",\"email\": \"root@localhost\",\"access_token\": true}" +# ``` +FEATURE_USER_INITIALIZE: true + +# Superusers have the following capabilities: +# - User management +# - Organization management +# - Service key management +# - Change log transparency +# - Usage log management +# - Globally-visible user message creation +SUPER_USERS: + - quayadmin + +# Mark initial setup as complete +SETUP_COMPLETE: true + +# Enable the new UI +FEATURE_UI_V2: true + +# Restrict the API to only allow XHR calls from the browser. Defaults to False. +BROWSER_API_CALLS_XHR_ONLY: false + +# Automatically create a namespace for each organization on push, if it doesn't already exist +CREATE_NAMESPACE_ON_PUSH: true + +# Whether users can directly login to the UI. Defaults to True +# FEATURE_DIRECT_LOGIN: true + +# Whether GitHub login is supported. Defaults to False +# FEATURE_GITHUB_LOGIN: false + +# Whether Google login is supported. Defaults to False +# FEATURE_GOOGLE_LOGIN: false + +# Whether users can be created (by non-super users). Defaults to True +FEATURE_USER_CREATION: false + +# Whether users being created must be invited by another user. Defaults to False +# FEATURE_INVITE_ONLY_USER_CREATION: false + +# If set to true, autocompletion will apply to partial usernames. Defaults to True +# FEATURE_PARTIAL_USER_AUTOCOMPLETE: true + +# Whether to record the last time a user was accessed. Defaults to True +# FEATURE_USER_LAST_ACCESSED: true + +# If set to true, users will have access to audit logs for their namespace. Defaults to False +FEATURE_USER_LOG_ACCESS: true + +# Whether to collect and support user metadata. Defaults to False +# FEATURE_USER_METADATA: false + +# If set to true, users can confirm their generated usernames. Defaults to True +# FEATURE_USERNAME_CONFIRMATION: true + +# If set to true, users can rename their own namespace. Defaults to False +FEATURE_USER_RENAME: true + +# Whether to allow anonymous users to browse and pull public repositories. Defaults to True +FEATURE_ANONYMOUS_ACCESS: false + +# The length of time a token for recovering a user accounts is valid. Defaults to 30m. +# USER_RECOVERY_TOKEN_LIFETIME: 30m + +# The time after which a fresh login requires users to reenter their password +# FRESH_LOGIN_TIMEOUT: 10m + +# Whether or not to rotate old action logs to storage. Defaults to False +# FEATURE_ACTION_LOG_ROTATION: false + +# If action log archiving is enabled, the path in storage in which to place the archived data. +# ACTION_LOG_ARCHIVE_PATH: + +# If action log archiving is enabled, the storage engine in which to place the archived data. +# ACTION_LOG_ARCHIVE_LOCATION: + +# Whether to proxy all direct download URLs in storage via the registry nginx. Defaults to False +# FEATURE_PROXY_STORAGE: false + +# Configuration for storage engine(s) to use in Quay. Each key is a unique ID for a storage engine, with the value being a tuple of the type and configuration for that engine. +# DISTRIBUTED_STORAGE_CONFIG: + +# If specified, the long-form title for the registry. Defaults to `Red Hat Quay`. +# REGISTRY_TITLE: Project Quay + +# If specified, the short-form title for the registry. Defaults to `Red Hat Quay`. +# REGISTRY_TITLE_SHORT: Project Quay + +# Number of results returned per page by search page. Defaults to 10 +# SEARCH_RESULTS_PER_PAGE: 10 + +# Maximum number of pages the user can paginate in search before they are limited. Defaults to 10 +# SEARCH_MAX_RESULT_PAGE_COUNT: 10 + +# If specified, contact information to display on the contact page. If only a single piece of contact information is specified, the contact footer will link directly. +# CONTACT_INFO: [] + +# The types of avatars to display, either generated inline (local) or Gravatar (gravatar) +# AVATAR_KIND: local + +# Custom branding for logos and URLs in the Quay UI +# BRANDING: + +# Root URL for documentation links +# DOCUMENTATION_ROOT: + +# Whether to allow for team membership to be synced from a backing group in the authentication engine (LDAP or Keystone) +# FEATURE_TEAM_SYNCING: false + +# If enabled, non-superusers can setup syncing on teams to backing LDAP or Keystone. Defaults To False. +# FEATURE_NONSUPERUSER_TEAM_SYNCING_SETUP: false + +# If team syncing is enabled for a team, how often to check its membership and resync if necessary (Default: 30m) +# TEAM_RESYNC_STALE_TIME: 30m + +# If enabled, users can create tokens for use by the Docker CLI. Defaults to True +# FEATURE_APP_SPECIFIC_TOKENS: true + +# Whether to turn of/off the security scanner. Defaults to False +FEATURE_SECURITY_SCANNER: true + +# If 'SECURITY_SCANNER_V4_SIGN_JWT', Quay will sign JWTs with either the key provided by `SECURITY_SCANNER_V4_PSK' or the Quay instance's private key otherwise. +SECURITY_SCANNER_V4_SIGN_JWT: true + +# The endpoint for the V2 security scanner +# SECURITY_SCANNER_ENDPOINT: + +# Whether or not to the security scanner notification feature +# SECURITY_SCANNER_NOTIFICATIONS: false + +# The number of seconds between indexing intervals in the security scanner. Defaults to 30. +# SECURITY_SCANNER_INDEXING_INTERVAL: 30 + +# The endpoint for the V4 security scanner +SECURITY_SCANNER_V4_ENDPOINT: http://localhost:6060 + +# The namespaces to which the security scanner should be enabled for +# SECURITY_SCANNER_V4_NAMESPACE_WHITELIST: [] + +# If 'SECURITY_SCANNER_V4_SIGN_JWT', Quay will sign JWTs with either the key provided by `SECURITY_SCANNER_V4_PSK' (if specified here) or the Quay instance's private key otherwise. +SECURITY_SCANNER_V4_PSK: 'REDACTEDREDACTEDREDACTED' + +# The issuer name to use in JWTs for the security scanner. +SECURITY_SCANNER_ISSUER_NAME: security_scanner + +# Whether to support Dockerfile build. Defaults to True +# FEATURE_BUILD_SUPPORT: + +# Configuration for using BitBucket for build triggers +# BITBUCKET_TRIGGER_CONFIG: + +# Whether to support Bitbucket build triggers. Defaults to False +# FEATURE_BITBUCKET_BUILD: false + +# Act as a proxy cache for upstream registries (e.g. Docker Hub, Quay.io, etc.) +FEATURE_PROXY_CACHE: true + +# Logs model for action logs +# LOGS_MODEL: database + +# Logs model config for action logs +# LOGS_MODEL_CONFIG: + +# Whether to support GitHub build triggers. Defaults to False +# FEATURE_GITHUB_BUILD: false + +# Configuration for using GitHub (Enterprise) for build triggers +# GITHUB_TRIGGER_CONFIG: + +# Configuration for using GitHub (Enterprise) as an external login provider +# GITHUB_LOGIN_CONFIG: + +# Whether to support GitLab build triggers. Defaults to False +# FEATURE_GITLAB_BUILD: false + +# Configuration for using Gitlab (Enterprise) for external authentication +# GITLAB_TRIGGER_CONFIG: + +# Configuration for using Google for external authentication +# GOOGLE_LOGIN_CONFIG: + +# The endpoint for JWT verification +# JWT_VERIFY_ENDPOINT: + +# The endpoint for JWT queries +# JWT_QUERY_ENDPOINT: + +# The endpoint for JWT users +# JWT_GETUSER_ENDPOINT: + +# The endpoint for JWT users +# JWT_AUTH_ISSUER: + +# Whether emails are enabled. Defaults to False +FEATURE_MAILING: false + +# If TLS is supported, but terminated at a layer before Quay, must be true. +# EXTERNAL_TLS_TERMINATION: false + +# Whether to enable support for repository mirroring. Defaults to False +FEATURE_REPO_MIRROR: true + +# Require HTTPS and verify certificates of Quay registry during mirror. Defaults to True +REPO_MIRROR_TLS_VERIFY: false + +# The number of seconds between checking for repository mirror candidates. Defaults to 30. +# REPO_MIRROR_INTERVAL: 30 + +# Replaces the SERVER_HOSTNAME as the destination for mirroring. Defaults to unset +# REPO_MIRROR_SERVER_HOSTNAME: + +# Maximum size in bytes of manifest list JSON to parse during mirroring. Prevents DoS via oversized manifests. Defaults to 10485760 (10MB). +# REPO_MIRROR_MAX_MANIFEST_LIST_SIZE: 10485760 + +# Maximum number of manifest entries to process during architecture-filtered mirroring. Prevents DoS via manifest lists with excessive entries. Defaults to 1000. +# REPO_MIRROR_MAX_MANIFEST_ENTRIES: 1000 + +# The SMTP server to use for sending e-mails. Only required if FEATURE_MAILING is set to true. +# MAIL_SERVER: + +# The SMTP port to use. If not specified, defaults to 587. +# MAIL_PORT: 587 + +# If set to true, no new User accounts may be created if their email domain is blacklisted. +# FEATURE_BLACKLISTED_EMAILS: false + +# The array of email-address domains that is used if FEATURE_BLACKLISTED_EMAILS is set to true. +# BLACKLISTED_EMAIL_DOMAINS: [] + +# Whether or not to use authentication for mail server. +# MAIL_USE_AUTH: false + +# The SMTP username to use when sending e-mails. +# MAIL_USERNAME: + +# The SMTP password to use when sending e-mails. +# MAIL_PASSWORD: + +# If specified, the e-mail address used as the `from` when Quay sends e-mails. If none, defaults to `support@quay.io`. +# MAIL_DEFAULT_SENDER: support@quay.io + +# If specified, whether to use TLS for sending e-mails. +# MAIL_USE_TLS: false + +# Whether users and organizations are allowed to change the tag expiration for tags in their namespace. Defaults to True. +# FEATURE_CHANGE_TAG_EXPIRATION: true + +# The options that users can select for expiration of tags in their namespace (if enabled) +# TAG_EXPIRATION_OPTIONS: [2w] + +# The default, configurable tag expiration time for time machine. Defaults to `2w`. +# DEFAULT_TAG_EXPIRATION: 2w + +# LDAP configuration for external authentication. Only required if AUTHENTICATION_TYPE is set to LDAP. +# LDAP_ADMIN_DN: +# LDAP_ADMIN_PASSWD: +# LDAP_URI: ldap://localhost +# LDAP_ALLOW_INSECURE_FALLBACK: false +# LDAP_BASE_DN: +# LDAP_USER_RDN: [] +# LDAP_UID_ATTR: uid +# LDAP_EMAIL_ATTR: mail +# LDAP_USER_FILTER: + +# If set to true, auto pruning of images is supported. Defaults to False +# FEATURE_AUTO_PRUNE: true + +# Default org wide auto prune policy. Defaults to empty +# DEFAULT_NAMESPACE_AUTOPRUNE_POLICY: diff --git a/cookbooks/quay/config/examples/clair/config.yaml b/cookbooks/quay/config/examples/clair/config.yaml new file mode 100644 index 0000000..9fa3654 --- /dev/null +++ b/cookbooks/quay/config/examples/clair/config.yaml @@ -0,0 +1,31 @@ +# Clair vulnerability scanner configuration +# Copy this file to /etc/quadlets/quay/clair-config.yaml and customize it. +# See https://quay.github.io/clair/reference/config.html for the full reference. +# +# Clair runs in combo mode: indexer, matcher and notifier all run in a single +# process sharing the same PostgreSQL database. + +http_listen_addr: ":6060" +introspection_addr: ":8089" +log_level: info + +indexer: + connstring: "host=127.0.0.1 port=5432 user=clair password=clair dbname=clair sslmode=disable" + migrations: true + +matcher: + connstring: "host=127.0.0.1 port=5432 user=clair password=clair dbname=clair sslmode=disable" + migrations: true + indexer_addr: http://localhost:6060 + +notifier: + connstring: "host=127.0.0.1 port=5432 user=clair password=clair dbname=clair sslmode=disable" + migrations: true + +auth: + psk: + # Pre-shared key for Clair <-> Quay authentication (must match config.yaml) + key: 'REDACTEDREDACTEDREDACTED' + iss: + - quay + - clairctl diff --git a/cookbooks/quay/config/examples/redis/redis.conf b/cookbooks/quay/config/examples/redis/redis.conf new file mode 100644 index 0000000..03c546f --- /dev/null +++ b/cookbooks/quay/config/examples/redis/redis.conf @@ -0,0 +1,10 @@ +# Network settings +port 6379 +bind 127.0.0.1 + +# Set a password for Redis +requirepass quay + +# Hybrid mode (AOF + RDB) +appendonly yes +aof-use-rdb-preamble yes diff --git a/cookbooks/quay/config/examples/redis/redis.env b/cookbooks/quay/config/examples/redis/redis.env new file mode 100644 index 0000000..0a8c543 --- /dev/null +++ b/cookbooks/quay/config/examples/redis/redis.env @@ -0,0 +1 @@ +REDISCLI_AUTH=quay diff --git a/cookbooks/quay/config/quay_load_tls_certs.sh b/cookbooks/quay/config/quay_load_tls_certs.sh new file mode 100755 index 0000000..672e6e6 --- /dev/null +++ b/cookbooks/quay/config/quay_load_tls_certs.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -Eeuo pipefail + +if ls /var/lib/quadlets/lego/certificates/*.crt &> /dev/null; then + echo "Lego-issued certificates found, loading them for Quay..." + install -o 10026 -g 10000 -m 0600 $(ls /var/lib/quadlets/lego/certificates/*.crt | head -1) /etc/quadlets/quay/app/ssl.cert + install -o 10026 -g 10000 -m 0600 $(ls /var/lib/quadlets/lego/certificates/*.key | head -1) /etc/quadlets/quay/app/ssl.key +elif [ ! -f /etc/quadlets/quay/app/ssl.cert ] && [ ! -f /etc/quadlets/quay/app/ssl.key ]; then + echo "No Lego-issued certificates found, generating self-signed certificates for Quay..." + openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /etc/quadlets/quay/app/ssl.key -out /etc/quadlets/quay/app/ssl.cert -subj "/CN=localhost" -addext "subjectAltName=DNS:localhost" + chown 10026:10000 /etc/quadlets/quay/app/ssl.{key,cert} + chmod 0600 /etc/quadlets/quay/app/ssl.{key,cert} +fi diff --git a/cookbooks/quay/other/postgresql/clair.sql b/cookbooks/quay/other/postgresql/clair.sql new file mode 100644 index 0000000..8771950 --- /dev/null +++ b/cookbooks/quay/other/postgresql/clair.sql @@ -0,0 +1,4 @@ +-- Initialization script for Clair database and user +CREATE USER clair WITH PASSWORD 'clair'; +CREATE DATABASE clair OWNER clair; +GRANT ALL PRIVILEGES ON DATABASE clair TO clair; diff --git a/cookbooks/quay/other/postgresql/quay.sh b/cookbooks/quay/other/postgresql/quay.sh new file mode 100755 index 0000000..f20f2a2 --- /dev/null +++ b/cookbooks/quay/other/postgresql/quay.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +set -Eeuo pipefail + +# Execute sql script, passed via stdin (or -f flag of pqsl) +# usage: docker_process_sql [psql-cli-args] +# ie: docker_process_sql --dbname=mydb <<<'INSERT ...' +# ie: docker_process_sql -f my-file.sql +# ie: docker_process_sql /dev/null; for try in $(seq 0 12); do if ! /bin/true 5<> /dev/tcp/127.0.0.1/5432; then echo "Waiting for PostgreSQL to be available..."; sleep 5; else exit 0; fi; done; exit 1' + +# Wait for Redis to be ready on localhost +ExecStartPre=/bin/sh -c 'exec 2>/dev/null; for try in $(seq 0 12); do if ! /bin/true 5<> /dev/tcp/127.0.0.1/6379; then echo "Waiting for Redis to be available..."; sleep 5; else exit 0; fi; done; exit 1' + +[Install] +WantedBy=quay.target diff --git a/cookbooks/quay/quay-app.image b/cookbooks/quay/quay-app.image new file mode 100644 index 0000000..a9294e6 --- /dev/null +++ b/cookbooks/quay/quay-app.image @@ -0,0 +1,6 @@ +[Unit] +Description=podman pull quay.io/projectquay/quay:3.17.1 +Documentation=https://docs.projectquay.io/ + +[Image] +Image=quay.io/projectquay/quay:3.17.1 diff --git a/cookbooks/quay/quay-clair.container b/cookbooks/quay/quay-clair.container new file mode 100644 index 0000000..304f481 --- /dev/null +++ b/cookbooks/quay/quay-clair.container @@ -0,0 +1,44 @@ +[Unit] +Description=Clair Vulnerability Scanner for Quay +Documentation=https://quay.github.io/clair/ +After=network.target + +# Only start if Clair has been configured +ConditionPathExists=/etc/quadlets/quay/clair/config.yaml + +# Start/stop this unit when the target is started/stopped +PartOf=quay.target + +[Container] +ContainerName=quay-clair +Image=quay-clair.image + +# Clair runs as the nobody user (65534) inside the container +User=65534 +Group=65534 + +# UID/GID mapping to map the nobody (65534) user inside the container to arbitrary user 10026 / group 10000 on the host +UIDMap=0:1000000:65535 +UIDMap=+65534:10026:1 +GIDMap=0:1000000:65535 +GIDMap=+65534:10000:1 + +# Network configuration +Network=host + +# Configuration +Volume=/etc/quadlets/quay/clair:/etc/clair:Z,ro + +# Run Clair in combo mode (indexer + matcher + notifier in a single process) +Exec=-conf /etc/clair/config.yaml + +[Service] +Restart=always +RestartSec=10 +TimeoutStartSec=120 + +# Wait for PostgreSQL to be ready on localhost +ExecStartPre=/bin/sh -c 'exec 2>/dev/null; for try in $(seq 0 12); do if ! /bin/true 5<> /dev/tcp/127.0.0.1/5432; then echo "Waiting for PostgreSQL to be available..."; sleep 5; else exit 0; fi; done; exit 1' + +[Install] +WantedBy=quay.target diff --git a/cookbooks/quay/quay-clair.image b/cookbooks/quay/quay-clair.image new file mode 100644 index 0000000..64d1bd3 --- /dev/null +++ b/cookbooks/quay/quay-clair.image @@ -0,0 +1,6 @@ +[Unit] +Description=podman pull quay.io/projectquay/clair:4.9.0 +Documentation=https://quay.github.io/clair/ + +[Image] +Image=quay.io/projectquay/clair:4.9.0 diff --git a/cookbooks/quay/quay-init-certificate.service b/cookbooks/quay/quay-init-certificate.service new file mode 100644 index 0000000..49f6a72 --- /dev/null +++ b/cookbooks/quay/quay-init-certificate.service @@ -0,0 +1,15 @@ +[Unit] +Description=Initialize Quay TLS certificates if not already present +Before=quay-app.service +After=lego.target + +# Start/stop this unit when the target is started/stopped +PartOf=quay.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/etc/quadlets/quay/quay_load_tls_certs.sh + +[Install] +WantedBy=quay.target diff --git a/cookbooks/quay/quay-load-renewed-certificate.service b/cookbooks/quay/quay-load-renewed-certificate.service new file mode 100644 index 0000000..481f876 --- /dev/null +++ b/cookbooks/quay/quay-load-renewed-certificate.service @@ -0,0 +1,17 @@ +[Unit] +Description=Reload Quay TLS certificate after Lego renewal +# Lego touches .renewed files when renewed certificates are available +ConditionPathExistsGlob=/var/lib/quadlets/lego/certificates/*.renewed +After=lego-renew.service + +[Service] +Type=oneshot +# Copy the renewed certificates to the Quay TLS directory +ExecStart=/etc/quadlets/quay/quay_load_tls_certs.sh +# Restart Quay to load the new certificate +ExecStart=systemctl --no-block restart quay-app.service +# Remove the flag files after restarting Quay +ExecStartPost=/bin/sh -Eeuo pipefail -c 'rm -f /var/lib/quadlets/lego/certificates/*.renewed' + +[Install] +WantedBy=lego-renew.service diff --git a/cookbooks/quay/quay-redis.container b/cookbooks/quay/quay-redis.container new file mode 100644 index 0000000..ba23f85 --- /dev/null +++ b/cookbooks/quay/quay-redis.container @@ -0,0 +1,49 @@ +[Unit] +Description=Redis cache for Quay +Documentation=https://hub.docker.com/_/redis +After=network.target var-lib-virtiofs-data.mount +Requires=var-lib-virtiofs-data.mount + +# Only start if Redis has been configured +ConditionPathExists=/etc/quadlets/quay/redis/redis.env +ConditionPathExists=/etc/quadlets/quay/redis/redis.conf + +# Start/stop this unit when the target is started/stopped +PartOf=quay.target + +[Container] +ContainerName=quay-redis +Image=quay-redis.image + +# Network configuration +Network=host + +# Redis configuration with authentication +Exec=redis-server /usr/local/etc/redis/redis.conf + +# No need for root privileges +User=10026 +Group=10000 + +# Storage +Volume=/var/lib/virtiofs/data/quay/redis:/data:Z +Volume=/etc/quadlets/quay/redis/redis.conf:/usr/local/etc/redis/redis.conf:ro,Z + +# Health check +HealthCmd=redis-cli -t 5 ping | grep -qFx PONG +HealthInterval=30s +HealthTimeout=5s +HealthStartPeriod=10s +HealthRetries=3 + +[Service] +Restart=always +RestartSec=10 +TimeoutStartSec=300 +TimeoutStopSec=30 + +# These environment variables are sourced to be used by systemd in the Exec* commands +EnvironmentFile=/etc/quadlets/quay/redis/redis.env + +[Install] +WantedBy=quay.target diff --git a/cookbooks/quay/quay-redis.image b/cookbooks/quay/quay-redis.image new file mode 100644 index 0000000..b483a9b --- /dev/null +++ b/cookbooks/quay/quay-redis.image @@ -0,0 +1,5 @@ +[Unit] +Description=podman pull docker.io/library/redis:7 + +[Image] +Image=docker.io/library/redis:7 diff --git a/cookbooks/quay/quay.target b/cookbooks/quay/quay.target new file mode 100644 index 0000000..2f3d51d --- /dev/null +++ b/cookbooks/quay/quay.target @@ -0,0 +1,13 @@ +[Unit] +Description=Quay Container Registry Target +Documentation=https://docs.projectquay.io/ +Requires=quay-redis.service quay-clair.service quay-app.service quay-init-certificate.service +After=quay-redis.service quay-clair.service quay-app.service quay-init-certificate.service + +# Allow isolation - can stop/start this target independently +AllowIsolate=yes +# Only start if Quay has been configured +ConditionPathExists=/etc/quadlets/quay/config.yaml + +[Install] +WantedBy=multi-user.target diff --git a/cookbooks/quay/tmpfiles.d/quay.conf b/cookbooks/quay/tmpfiles.d/quay.conf new file mode 100644 index 0000000..10f91a7 --- /dev/null +++ b/cookbooks/quay/tmpfiles.d/quay.conf @@ -0,0 +1,7 @@ +# Runtime directories for Quay +d /run/quadlets/quay 0755 10026 10000 - +d /run/quadlets/quay/tls 0700 10026 10000 - +# Persistent data directories for Quay +d /var/lib/virtiofs/data/quay 0700 10026 10000 - +d /var/lib/virtiofs/data/quay/redis 0700 10026 10000 - +d /var/lib/virtiofs/data/quay/storage 0700 10026 10000 -