diff --git a/.drone/drone.yml b/.drone/drone.yml deleted file mode 100644 index 58ef37c..0000000 --- a/.drone/drone.yml +++ /dev/null @@ -1,168 +0,0 @@ -kind: pipeline -type: docker -name: linux-amd64 - -platform: - arch: amd64 - os: linux - -steps: -- name: test - image: docker.io/drycc/go-dev - pull: always - privileged: true - commands: - - make docker-build test - environment: - VERSION: ${DRONE_TAG:-latest}-linux-amd64 - DEV_REGISTRY: ${DEV_REGISTRY:-docker.io} - DRYCC_REGISTRY: ${DRYCC_REGISTRY:-docker.io} - when: - event: - - push - - tag - - pull_request - volumes: - - name: image_registries - path: /etc/containers/registries.conf - -- name: publish - image: docker.io/drycc/go-dev - pull: always - privileged: true - commands: - - echo $DOCKER_PASSWORD | docker login --username $DOCKER_USERNAME --password-stdin - - make docker-build docker-immutable-push - environment: - VERSION: ${DRONE_TAG:-latest}-linux-amd64 - DEV_REGISTRY: - from_secret: dev_registry - DRYCC_REGISTRY: - from_secret: drycc_registry - DOCKER_USERNAME: - from_secret: docker_username - DOCKER_PASSWORD: - from_secret: docker_password - when: - event: - - push - - tag - volumes: - - name: image_registries - path: /etc/containers/registries.conf - -trigger: - event: - - push - - tag - - pull_request - -volumes: -- name: image_registries - host: - path: /etc/containers/registries.conf - ---- -kind: pipeline -type: docker -name: linux-arm64 - -platform: - arch: arm64 - os: linux - -steps: -- name: publish - image: docker.io/drycc/go-dev - pull: always - privileged: true - commands: - - echo $DOCKER_PASSWORD | docker login --username $DOCKER_USERNAME --password-stdin - - make docker-build docker-immutable-push - environment: - VERSION: ${DRONE_TAG:-latest}-linux-arm64 - DEV_REGISTRY: - from_secret: dev_registry - DRYCC_REGISTRY: - from_secret: drycc_registry - DOCKER_USERNAME: - from_secret: docker_username - DOCKER_PASSWORD: - from_secret: docker_password - volumes: - - name: image_registries - path: /etc/containers/registries.conf - -trigger: - event: - - push - - tag - -volumes: -- name: image_registries - host: - path: /etc/containers/registries.conf - ---- -kind: pipeline -type: docker -name: manifest - -steps: -- name: generate manifest - image: docker.io/library/alpine - pull: always - commands: - - sed -i "s/docker.io/$${DRYCC_REGISTRY}/g" .drone/manifest.tmpl - environment: - DRYCC_REGISTRY: - from_secret: drycc_registry - -- name: publish - image: plugins/manifest - settings: - spec: .drone/manifest.tmpl - username: - from_secret: docker_username - password: - from_secret: docker_password - environment: - DEV_REGISTRY: - from_secret: dev_registry - DRYCC_REGISTRY: - from_secret: drycc_registry - -trigger: - event: - - push - - tag - -depends_on: -- linux-amd64 -- linux-arm64 - ---- -kind: pipeline -type: docker -name: chart - -steps: -- name: generate chart - image: docker.io/drycc/python-dev - commands: - - IMAGE_TAG=$([ ! -z $DRONE_TAG ] && echo ${DRONE_TAG:1} || echo \"canary\") - - sed -i "s/image_tag:\ \"canary\"/image_tag:\ $IMAGE_TAG/g" charts/registry/values.yaml - - helm package charts/registry --version ${DRONE_TAG:-v1.0.0} - - curl -u $CHARTMUSEUM_USERNAME:$CHARTMUSEUM_PASSWORD -F chart=@registry-${DRONE_TAG:-v1.0.0}.tgz "$CHARTMUSEUM_API/api/$([ -z $DRONE_TAG ] && echo testing || echo stable)/charts" - environment: - CHARTMUSEUM_USERNAME: - from_secret: chartmuseum_username - CHARTMUSEUM_PASSWORD: - from_secret: chartmuseum_password - CHARTMUSEUM_API: - from_secret: chartmuseum_api - -trigger: - event: - - push - - tag diff --git a/.drone/manifest.tmpl b/.drone/manifest.tmpl deleted file mode 100644 index 6b5a36e..0000000 --- a/.drone/manifest.tmpl +++ /dev/null @@ -1,18 +0,0 @@ -image: docker.io/drycc/registry:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}canary{{/if}} -{{#if build.tags}} -tags: -{{#each build.tags}} - - {{this}} -{{/each}} -{{/if}} -manifests: - - - image: docker.io/drycc/registry:{{#if build.tag}}{{build.tag}}-{{else}}latest-{{/if}}linux-amd64 - platform: - architecture: amd64 - os: linux - - - image: docker.io/drycc/registry:{{#if build.tag}}{{build.tag}}-{{else}}latest-{{/if}}linux-arm64 - platform: - architecture: arm64 - os: linux diff --git a/.gitignore b/.gitignore index 5ed5b3e..e5361b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -rootfs/opt/ contrib/ci/tmp/ +.vscode/ +rootfs/opt/registry/sbin \ No newline at end of file diff --git a/.woodpecker/build-linux.yml b/.woodpecker/build-linux.yml new file mode 100644 index 0000000..ef4ecfd --- /dev/null +++ b/.woodpecker/build-linux.yml @@ -0,0 +1,35 @@ +matrix: + platform: + - linux/amd64 + - linux/arm64 + +labels: + type: exec + platform: ${platform} + +steps: +- name: publish-linux + image: bash + commands: + - export VERSION=$([ -z $CI_COMMIT_TAG ] && echo latest || echo $CI_COMMIT_TAG)-$(sed 's#/#-#g' <<< $CI_SYSTEM_PLATFORM) + - echo $CONTAINER_PASSWORD | podman login $DRYCC_REGISTRY --username $CONTAINER_USERNAME --password-stdin > /dev/null 2>&1 + - make podman-build podman-immutable-push + environment: + CODENAME: + from_secret: codename + DEV_REGISTRY: + from_secret: dev_registry + DRYCC_REGISTRY: + from_secret: drycc_registry + CONTAINER_USERNAME: + from_secret: container_username + CONTAINER_PASSWORD: + from_secret: container_password + when: + event: + - push + - tag + - cron + +depends_on: +- test-linux \ No newline at end of file diff --git a/.woodpecker/chart.yaml b/.woodpecker/chart.yaml new file mode 100644 index 0000000..cfcd3ec --- /dev/null +++ b/.woodpecker/chart.yaml @@ -0,0 +1,33 @@ +labels: + type: exec + platform: linux/amd64 + +steps: +- name: generate-chart + image: bash + commands: + - export VERSION=$(sed 's#v##' <<< $CI_COMMIT_TAG) + - export IMAGE_TAG=$([ ! -z $CI_COMMIT_TAG ] && echo \"$VERSION\" || echo \"canary\") + - export APP_VERSION=$([ -z $CI_COMMIT_TAG ] && echo $CI_COMMIT_SHA || echo $VERSION) + - export CHART_VERSION=$([ -z $CI_COMMIT_TAG ] && echo 1.0.0 || echo $VERSION) + - sed -i "s/imageTag:\ \"canary\"/imageTag:\ $IMAGE_TAG/g" charts/$${CI_REPO_NAME}/values.yaml + - helm package -u charts/$${CI_REPO_NAME} --version $CHART_VERSION --app-version $APP_VERSION + - echo $CONTAINER_PASSWORD | helm registry login $DRYCC_REGISTRY -u $CONTAINER_USERNAME --password-stdin + - helm push $${CI_REPO_NAME}-$CHART_VERSION.tgz oci://$DRYCC_REGISTRY/$([ -z $CI_COMMIT_TAG ] && echo charts-testing || echo charts) + environment: + DEV_REGISTRY: + from_secret: dev_registry + DRYCC_REGISTRY: + from_secret: drycc_registry + CONTAINER_USERNAME: + from_secret: container_username + CONTAINER_PASSWORD: + from_secret: container_password + when: + event: + - push + - tag + - cron + +depends_on: +- manifest diff --git a/.woodpecker/manifest.tmpl b/.woodpecker/manifest.tmpl new file mode 100644 index 0000000..8739535 --- /dev/null +++ b/.woodpecker/manifest.tmpl @@ -0,0 +1,18 @@ +image: registry.drycc.cc/drycc/{{project}}:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}canary{{/if}} +{{#if build.tags}} +tags: +{{#each build.tags}} + - {{this}} +{{/each}} +{{/if}} +manifests: + - + image: registry.drycc.cc/drycc/{{project}}:{{#if build.tag}}{{build.tag}}-{{else}}latest-{{/if}}linux-amd64 + platform: + architecture: amd64 + os: linux + - + image: registry.drycc.cc/drycc/{{project}}:{{#if build.tag}}{{build.tag}}-{{else}}latest-{{/if}}linux-arm64 + platform: + architecture: arm64 + os: linux diff --git a/.woodpecker/manifest.yml b/.woodpecker/manifest.yml new file mode 100644 index 0000000..19fc70c --- /dev/null +++ b/.woodpecker/manifest.yml @@ -0,0 +1,43 @@ +labels: + type: exec + platform: linux/amd64 + +steps: +- name: generate-manifest + image: bash + commands: + - sed -i "s/{{project}}/$${CI_REPO_NAME}/g" .woodpecker/manifest.tmpl + - sed -i "s/registry.drycc.cc/$${DRYCC_REGISTRY}/g" .woodpecker/manifest.tmpl + environment: + DRYCC_REGISTRY: + from_secret: drycc_registry + when: + event: + - tag + - push + - cron + +- name: publish-manifest + image: bash + commands: + - podman run --rm + -e PLUGIN_SPEC=.woodpecker/manifest.tmpl + -e PLUGIN_USERNAME=$CONTAINER_USERNAME + -e PLUGIN_PASSWORD=$CONTAINER_PASSWORD + -e DRONE_TAG=$CI_COMMIT_TAG + -v $(pwd):$(pwd) + -w $(pwd) + docker.io/plugins/manifest + environment: + CONTAINER_USERNAME: + from_secret: container_username + CONTAINER_PASSWORD: + from_secret: container_password + when: + event: + - tag + - push + - cron + +depends_on: +- build-linux diff --git a/.woodpecker/test-linux.yml b/.woodpecker/test-linux.yml new file mode 100644 index 0000000..194832f --- /dev/null +++ b/.woodpecker/test-linux.yml @@ -0,0 +1,24 @@ +matrix: + platform: + - linux/amd64 + - linux/arm64 + +labels: + type: exec + platform: ${platform} + +steps: +- name: test-linux + image: bash + commands: + - make test + environment: + CODENAME: + from_secret: codename + DEV_REGISTRY: + from_secret: dev_registry + when: + event: + - push + - tag + - cron diff --git a/Dockerfile b/Dockerfile index 7d18242..e9e37c3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,24 +1,55 @@ -FROM docker.io/minio/mc:latest as mc +ARG CODENAME - -FROM docker.io/drycc/go-dev:latest AS build +FROM registry.drycc.cc/drycc/go-dev:latest AS build ARG LDFLAGS -ADD . /app +ADD . /workspace RUN export GO111MODULE=on \ - && cd /app \ - && CGO_ENABLED=0 go build -ldflags "${LDFLAGS}" -o /usr/local/bin/registry main.go \ - && upx -9 --brute /usr/local/bin/registry + && cd /workspace \ + && CGO_ENABLED=0 init-stack go build -ldflags "${LDFLAGS}" -o /bin/start-registry main.go \ + && upx -9 --brute /bin/start-registry + + +FROM registry.drycc.cc/drycc/base:${CODENAME} +ARG DRYCC_UID=1001 \ + DRYCC_GID=1001 \ + DRYCC_HOME_DIR=/var/lib/registry \ + JQ_VERSION="1.7.1" \ + NGINX_VERSION="1.29.1" \ + RCLONE_VERSION="1.71.1" \ + REGISTRY_VERSION="3.0.0" -FROM docker.io/library/registry:2.7 +RUN groupadd drycc --gid ${DRYCC_GID} \ + && useradd drycc -u ${DRYCC_UID} -g ${DRYCC_GID} -s /bin/bash -m -d ${DRYCC_HOME_DIR} \ + && install-packages apache2-utils \ + && install-stack jq $JQ_VERSION \ + && install-stack nginx ${NGINX_VERSION} \ + && install-stack rclone $RCLONE_VERSION \ + && install-stack registry $REGISTRY_VERSION \ + && rm -rf \ + /usr/share/doc \ + /usr/share/man \ + /usr/share/info \ + /usr/share/locale \ + /var/lib/apt/lists/* \ + /var/log/* \ + /var/cache/debconf/* \ + /etc/systemd \ + /lib/lsb \ + /lib/udev \ + /usr/lib/`echo $(uname -m)`-linux-gnu/gconv/IBM* \ + /usr/lib/`echo $(uname -m)`-linux-gnu/gconv/EBC* \ + && mkdir -p /usr/share/man/man{1..8} \ + && chown -R ${DRYCC_UID}:${DRYCC_GID} /opt/drycc -COPY rootfs / -COPY --from=mc /usr/bin/mc /bin/mc -COPY --from=build /usr/local/bin/registry /opt/registry/sbin/registry +COPY --from=build /bin/start-registry /bin/start-registry +COPY --chown=${DRYCC_UID}:${DRYCC_GID} rootfs/bin/ /bin/ +COPY --chown=${DRYCC_UID}:${DRYCC_GID} rootfs/opt/drycc/nginx /opt/drycc/nginx +COPY --chown=${DRYCC_UID}:${DRYCC_GID} rootfs/config-example.yml /opt/drycc/registry/etc/config.yml -RUN apk add --no-cache jq bash \ - && chmod +x /bin/create_bucket /bin/normalize_storage +ENV OTEL_TRACES_EXPORTER=none \ + DRYCC_REGISTRY_CONFIG=/opt/drycc/registry/etc/config.yml -VOLUME ["/var/lib/registry"] -CMD ["/opt/registry/sbin/registry"] +USER ${DRYCC_UID} +VOLUME ["${DRYCC_HOME_DIR}"] EXPOSE 5000 diff --git a/Makefile b/Makefile index 1dc469b..7fce73e 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # Short name: Short name, following [a-zA-Z_], used all over the place. # Some uses for short name: -# - Docker image name +# - Container image name # - Kubernetes service, deployment, pod names SHORT_NAME := registry DRYCC_REGISTRY ?= ${DEV_REGISTRY} @@ -16,8 +16,8 @@ SHELL_SCRIPTS = $(wildcard rootfs/bin/* _scripts/*.sh contrib/ci/*.sh) # The following variables describe the containerized development environment # and other build options DEV_ENV_IMAGE := ${DEV_REGISTRY}/drycc/go-dev -DEV_ENV_WORK_DIR := /go/src/${REPO_PATH} -DEV_ENV_PREFIX := docker run --rm -v ${CURDIR}:${DEV_ENV_WORK_DIR} -w ${DEV_ENV_WORK_DIR} +DEV_ENV_WORK_DIR := /opt/drycc/go/src/${REPO_PATH} +DEV_ENV_PREFIX := podman run --rm -v ${CURDIR}:${DEV_ENV_WORK_DIR} -w ${DEV_ENV_WORK_DIR} DEV_ENV_CMD := ${DEV_ENV_PREFIX} ${DEV_ENV_IMAGE} LDFLAGS := "-s -w -X main.version=${VERSION}" BINDIR := ./rootfs/opt/registry/sbin @@ -29,31 +29,28 @@ endif all: @echo "Use a Makefile to control top-level building of the project." -build: check-docker +build: check-podman mkdir -p ${BINDIR} $(MAKE) build-binary # For cases where we're building from local # We also alter the RC file to set the image name. -docker-build: check-docker - docker build ${DOCKER_BUILD_FLAGS} -t ${IMAGE} --build-arg LDFLAGS=${LDFLAGS} . - docker tag ${IMAGE} ${MUTABLE_IMAGE} - -docker-buildx: check-docker - docker buildx build --platform ${PLATFORM} -t ${IMAGE} --build-arg LDFLAGS=${LDFLAGS} . --push +podman-build: check-podman + podman build --build-arg CODENAME=${CODENAME} -t ${IMAGE} --build-arg LDFLAGS=${LDFLAGS} . + podman tag ${IMAGE} ${MUTABLE_IMAGE} build-binary: ${DEV_ENV_CMD} go build -ldflags ${LDFLAGS} -o $(BINDIR)/${SHORT_NAME} main.go $(call check-static-binary,$(BINDIR)/${SHORT_NAME}) ${DEV_ENV_CMD} upx -9 --brute $(BINDIR)/${SHORT_NAME} -test: check-docker test-style +test: check-podman podman-build test-style contrib/ci/test.sh ${IMAGE} test-style: ${DEV_ENV_CMD} shellcheck $(SHELL_SCRIPTS) -deploy: check-kubectl docker-build docker-push +deploy: check-kubectl podman-build podman-push kubectl --namespace=drycc patch deployment drycc-$(SHORT_NAME) --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"$(IMAGE)"}]' -.PHONY: all build build-binary docker-build test test-style deploy +.PHONY: all build build-binary podman-build test test-style deploy diff --git a/README.md b/README.md index d3c5a7a..ae7eea3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Drycc Registry v2 -[![Build Status](https://drone.drycc.cc/api/badges/drycc/registry/status.svg)](https://drone.drycc.cc/drycc/registry) +[![Build Status](https://woodpecker.drycc.cc/api/badges/drycc/registry/status.svg)](https://woodpecker.drycc.cc/drycc/registry) [![Go Report Card](https://goreportcard.com/badge/github.com/drycc/registry)](https://goreportcard.com/report/github.com/drycc/registry) @@ -12,11 +12,19 @@ We welcome your input! If you have feedback, please submit an [issue][issues]. I # About -The registry is a [Docker registry](https://docs.docker.com/registry/) component for use in Kubernetes. While it's intended for use inside of the Drycc open source [PaaS](https://en.wikipedia.org/wiki/Platform_as_a_service), it's flexible enough to be used as a standalone pod on any Kubernetes cluster. +Registry consists of two components, namely the proxy component and the registry component. -If you decide to use this component standalone, you can host your own Docker registry in your own Kubernetes cluster. +## Proxy -The Docker image that this repository builds is based on [the official Docker v2 registry image](https://github.com/docker/distribution). +The proxy component is a proxy deployed on every Kubernetes worker node, proxying all requests to the Drycc Workflow [registry][registry]. This allows the worker nodes daemons to communicate to the registry over localhost, bypassing the need for adding the `--insecure-registry` flag to the daemons. + +## Registry + +The registry component is a [Container registry](https://github.com/distribution/distribution) component for use in Kubernetes. While it's intended for use inside of the Drycc open source [PaaS](https://en.wikipedia.org/wiki/Platform_as_a_service), it's flexible enough to be used as a standalone pod on any Kubernetes cluster. + +If you decide to use this component standalone, you can host your own Container registry in your own Kubernetes cluster. + +The Container image that this repository builds is based on [the official Container v2 registry image](https://github.com/distribution/distribution). # Development @@ -49,7 +57,7 @@ $ export IMAGE_PREFIX=youruser/ # if using Quay or Dockerhub To build and push the image run: ```console -$ make docker-build docker-push +$ make podman-build podman-push ``` To deploy the image via patching the registry deployment run: diff --git a/charts/registry/Chart.yaml b/charts/registry/Chart.yaml index bbe1197..cd8abff 100644 --- a/charts/registry/Chart.yaml +++ b/charts/registry/Chart.yaml @@ -1,7 +1,13 @@ name: registry home: https://github.com/drycc/registry -version: v1.0.0 -description: Docker registry for Drycc Workflow. +apiVersion: v2 +appVersion: 1.0.0 +dependencies: + - name: common + repository: oci://registry.drycc.cc/charts + version: ~1.1.2 +description: Container registry for Drycc Workflow. maintainers: - name: Drycc Team email: engineering@drycc.com +version: v1.1.0 diff --git a/charts/registry/templates/_helper.tpl b/charts/registry/templates/_helper.tpl new file mode 100644 index 0000000..cd87b72 --- /dev/null +++ b/charts/registry/templates/_helper.tpl @@ -0,0 +1,71 @@ +{{- define "registry.envs" }} +env: +- name: REGISTRY_STORAGE_DELETE_ENABLED + value: "true" +- name: REGISTRY_LOG_LEVEL + value: info +- name: "REGISTRY_HTTP_SECRET" + valueFrom: + secretKeyRef: + name: registry-secret + key: secret +- name: "DRYCC_REGISTRY_REDIRECT" + valueFrom: + secretKeyRef: + name: registry-secret + key: redirect +- name: "DRYCC_REGISTRY_USERNAME" + valueFrom: + secretKeyRef: + name: registry-secret + key: username +- name: "DRYCC_REGISTRY_PASSWORD" + valueFrom: + secretKeyRef: + name: registry-secret + key: password +{{- if (.Values.storageEndpoint) }} +- name: "DRYCC_STORAGE_BUCKET" + valueFrom: + secretKeyRef: + name: registry-secret + key: storage-bucket +- name: "DRYCC_STORAGE_ENDPOINT" + valueFrom: + secretKeyRef: + name: registry-secret + key: storage-endpoint +- name: "DRYCC_STORAGE_ACCESSKEY" + valueFrom: + secretKeyRef: + name: registry-secret + key: storage-accesskey +- name: "DRYCC_STORAGE_SECRETKEY" + valueFrom: + secretKeyRef: + name: registry-secret + key: storage-secretkey +- name: "DRYCC_STORAGE_PATH_STYLE" + valueFrom: + secretKeyRef: + name: registry-secret + key: storage-path-style +{{- else if .Values.storage.enabled }} +- name: "DRYCC_STORAGE_BUCKET" + value: "registry" +- name: "DRYCC_STORAGE_ENDPOINT" + value: http://drycc-storage:9000 +- name: "DRYCC_STORAGE_ACCESSKEY" + valueFrom: + secretKeyRef: + name: storage-creds + key: accesskey +- name: "DRYCC_STORAGE_SECRETKEY" + valueFrom: + secretKeyRef: + name: storage-creds + key: secretkey +- name: "DRYCC_STORAGE_PATH_STYLE" + value: "true" +{{- end }} +{{- end }} diff --git a/charts/registry/templates/registry-cronjob-daily.yaml b/charts/registry/templates/registry-cronjob-daily.yaml new file mode 100644 index 0000000..442841b --- /dev/null +++ b/charts/registry/templates/registry-cronjob-daily.yaml @@ -0,0 +1,46 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: drycc-registry-cronjob-daily + labels: + heritage: drycc + annotations: + component.drycc.cc/version: {{ .Values.imageTag }} +spec: + schedule: "0 0 * * *" + concurrencyPolicy: {{ .Values.concurrencyPolicy }} + successfulJobsHistoryLimit: 1 + failedJobsHistoryLimit: 1 + jobTemplate: + spec: + template: + spec: + restartPolicy: OnFailure + serviceAccount: drycc-controller + initContainers: + - name: drycc-registry-init + image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/python-dev:latest + imagePullPolicy: {{.Values.imagePullPolicy}} + args: + - netcat + - -v + - -u + - $(DRYCC_STORAGE_ENDPOINT) + {{- include "registry.envs" . | indent 12 }} + containers: + - image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/registry:{{.Values.imageTag}} + imagePullPolicy: {{.Values.imagePullPolicy}} + name: drycc-registry-garbage-collect + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 14 }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 14 }} + {{- else }} + args: + - /usr/bin/env + - bash + - -ec + - | + # run garbage collect + start-registry garbage-collect ${DRYCC_REGISTRY_CONFIG} --dry-run --delete-untagged + {{- end }} + {{- include "registry.envs" . | indent 12 }} diff --git a/charts/registry/templates/registry-deployment.yaml b/charts/registry/templates/registry-deployment.yaml index facffc0..dc362e3 100644 --- a/charts/registry/templates/registry-deployment.yaml +++ b/charts/registry/templates/registry-deployment.yaml @@ -1,4 +1,3 @@ -{{- if eq .Values.global.registry_location "on-cluster" }} apiVersion: apps/v1 kind: Deployment metadata: @@ -6,9 +5,9 @@ metadata: labels: heritage: drycc annotations: - component.drycc.cc/version: {{ .Values.image_tag }} + component.drycc.cc/version: {{ .Values.imageTag }} spec: - replicas: 1 + replicas: {{ .Values.replicas }} strategy: rollingUpdate: maxSurge: 1 @@ -19,61 +18,78 @@ spec: app: drycc-registry template: metadata: - labels: + labels: {{- include "common.labels.standard" . | nindent 8 }} app: drycc-registry spec: + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAffinityPreset.type "component" "" "extraMatchLabels" .Values.podAffinityPreset.extraMatchLabels "topologyKey" "" "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAntiAffinityPreset.type "component" "" "extraMatchLabels" .Values.podAntiAffinityPreset.extraMatchLabels "topologyKey" "" "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.nodeAffinityPreset.type "key" .Values.nodeAffinityPreset.key "values" .Values.nodeAffinityPreset.values ) | nindent 10 }} serviceAccount: drycc-registry initContainers: - name: drycc-registry-init - image: docker.io/drycc/python-dev:latest - imagePullPolicy: {{.Values.image_pull_policy}} - command: - - netcat - - -v - - -a - - $(DRYCC_MINIO_SERVICE_HOST):$(DRYCC_MINIO_SERVICE_PORT) + image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/python-dev:latest + imagePullPolicy: {{.Values.imagePullPolicy}} + args: + - netcat + - -v + - -u + - $(DRYCC_STORAGE_ENDPOINT) + {{- include "registry.envs" . | indent 8 }} containers: - name: drycc-registry - image: {{.Values.image_registry}}/{{.Values.image_org}}/registry:{{.Values.image_tag}} - imagePullPolicy: {{.Values.image_pull_policy}} -{{- if or (.Values.limits_cpu) (.Values.limits_memory)}} + image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/registry:{{.Values.imageTag}} + imagePullPolicy: {{.Values.imagePullPolicy}} + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 10 }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 10 }} + {{- else }} + args: + - start-registry + {{- end }} + {{- with index .Values "resources" }} resources: - limits: -{{- if (.Values.limits_cpu) }} - cpu: {{.Values.limits_cpu}} -{{- end}} -{{- if (.Values.limits_memory) }} - memory: {{.Values.limits_memory}} -{{- end}} -{{- end}} + {{- toYaml . | nindent 10 }} + {{- end }} + {{- include "registry.envs" . | indent 8 }} + {{- if not .Values.diagnosticMode.enabled }} + startupProbe: + tcpSocket: + port: 5000 + initialDelaySeconds: 30 + periodSeconds: 5 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 5 livenessProbe: httpGet: - path: /v2/ + path: / port: 5000 - initialDelaySeconds: 1 + initialDelaySeconds: 30 + periodSeconds: 5 timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 5 readinessProbe: httpGet: - path: /v2/ + path: / port: 5000 - initialDelaySeconds: 1 + initialDelaySeconds: 30 + periodSeconds: 5 timeoutSeconds: 1 - env: - - name: REGISTRY_STORAGE_DELETE_ENABLED - value: "true" - - name: REGISTRY_LOG_LEVEL - value: info + successThreshold: 1 + failureThreshold: 5 + {{- end }} ports: - - containerPort: 5000 + - containerPort: 5000 + name: http volumeMounts: - - name: registry-storage - mountPath: /var/lib/registry - - name: objectstorage-creds - mountPath: /var/run/secrets/drycc/objectstore/creds - volumes: - name: registry-storage - emptyDir: {} - - name: objectstorage-creds - secret: - secretName: objectstorage-keyfile -{{- end }} + mountPath: /var/lib/registry + securityContext: + fsGroup: 1001 + runAsGroup: 1001 + runAsUser: 1001 + volumes: + - name: registry-storage + emptyDir: {} diff --git a/charts/registry/templates/registry-proxy-daemonset.yaml b/charts/registry/templates/registry-proxy-daemonset.yaml new file mode 100644 index 0000000..c83a364 --- /dev/null +++ b/charts/registry/templates/registry-proxy-daemonset.yaml @@ -0,0 +1,98 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: drycc-registry-proxy + labels: + heritage: drycc + annotations: + component.drycc.cc/version: {{ .Values.imageTag }} +spec: + updateStrategy: + type: RollingUpdate + selector: + matchLabels: + app: drycc-registry-proxy + heritage: drycc + template: + metadata: + name: drycc-registry-proxy + labels: + heritage: drycc + app: drycc-registry-proxy + spec: + securityContext: + fsGroup: 1001 + runAsGroup: 1001 + runAsUser: 1001 + initContainers: + - name: drycc-registry-init + image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/python-dev:latest + imagePullPolicy: {{.Values.imagePullPolicy}} + args: + - netcat + - -v + - -a + - $(DRYCC_REGISTRY_HOST) + env: + - name: "DRYCC_REGISTRY_HOST" + value: drycc-registry:5000 + containers: + - name: drycc-registry-proxy + image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/registry:{{.Values.imageTag}} + imagePullPolicy: {{.Values.imagePullPolicy}} + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 10 }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 10 }} + {{- else }} + args: + - start-proxy + {{- end }} + {{- with index .Values "proxy" "resources" }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- if not .Values.diagnosticMode.enabled }} + startupProbe: + httpGet: + path: / + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 5 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 5 + livenessProbe: + httpGet: + path: / + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 5 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 5 + readinessProbe: + httpGet: + path: / + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 5 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 5 + {{- end }} + env: + - name: "DRYCC_REGISTRY_HOST" + value: drycc-registry:5000 + - name: "DRYCC_REGISTRY_USERNAME" + valueFrom: + secretKeyRef: + name: registry-secret + key: username + - name: "DRYCC_REGISTRY_PASSWORD" + valueFrom: + secretKeyRef: + name: registry-secret + key: password + ports: + - containerPort: 8080 + hostPort: {{.Values.proxy.port}} diff --git a/charts/registry/templates/registry-secret.yaml b/charts/registry/templates/registry-secret.yaml new file mode 100644 index 0000000..9fa12be --- /dev/null +++ b/charts/registry/templates/registry-secret.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Secret +metadata: + name: registry-secret + labels: + heritage: drycc +type: Opaque +data: + secret: {{ include "common.secrets.lookup" (dict "secret" "registry-secret" "key" "secret" "defaultValue" (randAlphaNum 32) "context" $) }} + username: {{ include "common.secrets.lookup" (dict "secret" "registry-secret" "key" "username" "defaultValue" (.Values.username | default (randAlphaNum 32)) "context" $) }} + password: {{ include "common.secrets.lookup" (dict "secret" "registry-secret" "key" "password" "defaultValue" (.Values.password | default (randAlphaNum 32)) "context" $) }} + redirect: {{ .Values.redirect | b64enc }} + {{- if (.Values.storageEndpoint) }} + storage-bucket: {{ .Values.storageBucket | b64enc }} + storage-endpoint: {{ .Values.storageEndpoint | b64enc }} + storage-accesskey: {{ .Values.storageAccesskey | b64enc }} + storage-secretkey: {{ .Values.storageSecretkey | b64enc }} + storage-path-style: {{ .Values.storagePathStyle | b64enc }} + {{- end }} diff --git a/charts/registry/templates/registry-service-account.yaml b/charts/registry/templates/registry-service-account.yaml index f117ae3..a3b2b78 100644 --- a/charts/registry/templates/registry-service-account.yaml +++ b/charts/registry/templates/registry-service-account.yaml @@ -1,8 +1,6 @@ -{{- if eq .Values.global.registry_location "on-cluster" }} apiVersion: v1 kind: ServiceAccount metadata: name: drycc-registry labels: heritage: drycc -{{- end }} diff --git a/charts/registry/templates/registry-service.yaml b/charts/registry/templates/registry-service.yaml index be960ac..fbafcf2 100644 --- a/charts/registry/templates/registry-service.yaml +++ b/charts/registry/templates/registry-service.yaml @@ -1,16 +1,17 @@ -{{- if eq .Values.global.registry_location "on-cluster" }} apiVersion: v1 kind: Service metadata: name: drycc-registry + annotations: + prometheus.io/path: /metrics + prometheus.io/port: "9000" + prometheus.io/scrape: "true" + {{- with .Values.service.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} labels: heritage: drycc spec: - ports: - - name: http - port: 80 - targetPort: 5000 + clusterIP: None selector: app: drycc-registry - sessionAffinity: ClientIP -{{- end }} diff --git a/charts/registry/values.yaml b/charts/registry/values.yaml index 14c748b..87a2895 100644 --- a/charts/registry/values.yaml +++ b/charts/registry/values.yaml @@ -1,6 +1,84 @@ -image_org: "drycc" -image_pull_policy: "Always" -image_tag: "canary" -image_registry: "docker.io" -# limits_cpu: "100m" -# limits_memory: "50Mi" +imageOrg: "drycc" +imagePullPolicy: "Always" +imageTag: "canary" +imageRegistry: "registry.drycc.cc" + +## Enable diagnostic mode +## +diagnosticMode: + ## @param diagnosticMode.enabled Enable diagnostic mode (all probes will be disabled and the command will be overridden) + ## + enabled: false + ## @param diagnosticMode.command Command to override all containers + ## + command: + - sleep + ## @param diagnosticMode.args Args to override all containers + ## + args: + - infinity + +nodeAffinityPreset: + key: "drycc.cc/node" + type: "soft" + values: + - "true" + +podAffinityPreset: + type: "" + extraMatchLabels: + security: "drycc-security" + +podAntiAffinityPreset: + type: "soft" + extraMatchLabels: + app: "drycc-registry" + +# registry replicas +replicas: 1 +# registry storage redirect +redirect: "false" + +proxy: + # host port for the registry proxy in the daemonset + port: 5555 + resources: {} + # limits: + # cpu: 200m + # memory: 50Mi + # requests: + # cpu: 100m + # memory: 30Mi + +resources: {} + # limits: + # cpu: 200m + # memory: 50Mi + # requests: + # cpu: 100m + # memory: 30Mi + +concurrencyPolicy: "Replace" + +# The following parameters will no longer use the built-in storage component. +storageBucket: "builder" +storageEndpoint: "" +storageAccesskey: "" +storageSecretkey: "" +storagePathStyle: "auto" + +storage: + enabled: true + +# Service +service: + # Provide any additional service annotations + annotations: {} + +resources: {} + # limits: + # cpu: 200m + # memory: 50Mi + # requests: + # cpu: 100m + # memory: 30Mi diff --git a/contrib/ci/test.sh b/contrib/ci/test.sh index a0c143c..6be70b3 100755 --- a/contrib/ci/test.sh +++ b/contrib/ci/test.sh @@ -2,33 +2,73 @@ set -eoxf pipefail -CURRENT_DIR=$(cd "$(dirname "$0")"; pwd) +DRYCC_STORAGE_ACCESSKEY=f4c4281665bc11ee8e0400163e04a9cd +DRYCC_STORAGE_SECRETKEY=f4c4281665bc11ee8e0400163e04a9cd -mkdir -p "${CURRENT_DIR}"/tmp/aws-user -echo "us-east-1" > "${CURRENT_DIR}"/tmp/aws-user/region -echo "registry-bucket" > "${CURRENT_DIR}"/tmp/aws-user/registry-bucket -echo "1234567890123456789012345678901234567890" > "${CURRENT_DIR}"/tmp/aws-user/accesskey -echo "1234567890123456789012345678901234567890" > "${CURRENT_DIR}"/tmp/aws-user/secretkey -MINIO_JOB=$(docker run -d --name minio \ - -v "${CURRENT_DIR}"/tmp/aws-user:/var/run/secrets/drycc/objectstore/creds \ - drycc/minio:canary server /home/minio/) +STORAGE_JOB=$(podman run -d --rm --entrypoint init-stack \ + -e RUSTFS_ACCESS_KEY="${DRYCC_STORAGE_ACCESSKEY}" \ + -e RUSTFS_SECRET_KEY="${DRYCC_STORAGE_SECRETKEY}" \ + "${DEV_REGISTRY}"/drycc/storage:canary rustfs /data) -sleep 5 -docker logs "${MINIO_JOB}" +# wait for port +STORAGE_IP=$(podman inspect --format "{{ .NetworkSettings.IPAddress }}" "${STORAGE_JOB}") +echo -e "\\033[32m---> Waitting for ${STORAGE_IP}:9000\\033[0m" +wait-for-port --host="${STORAGE_IP}" 9000 +echo -e "\\033[32m---> S3 service ${STORAGE_IP}:9000 ready...\\033[0m" +podman logs "${STORAGE_JOB}" -MINIO_IP=$(docker inspect --format "{{ .NetworkSettings.IPAddress }}" "${MINIO_JOB}") +REGISTRY_JOB=$(podman run -d --rm \ + -e DRYCC_REGISTRY_REDIRECT=false \ + -e DRYCC_REGISTRY_USERNAME=admin \ + -e DRYCC_REGISTRY_PASSWORD=admin \ + -e DRYCC_STORAGE_BUCKET=registry \ + -e DRYCC_STORAGE_ENDPOINT="http://${STORAGE_IP}:9000" \ + -e DRYCC_STORAGE_ACCESSKEY="${DRYCC_STORAGE_ACCESSKEY}" \ + -e DRYCC_STORAGE_SECRETKEY="${DRYCC_STORAGE_SECRETKEY}" \ + -e DRYCC_STORAGE_PATH_STYLE=true \ + "$1" start-registry) -JOB=$(docker run --add-host minio:"${MINIO_IP}" \ - -d \ - -e DRYCC_MINIO_SERVICE_HOST=minio \ - -e DRYCC_MINIO_SERVICE_PORT=9000 \ - -v "${CURRENT_DIR}"/tmp/aws-user:/var/run/secrets/drycc/objectstore/creds \ - "$1") +# shellcheck disable=SC2317 +function clean_before_exit { + # delay before exiting, so stdout/stderr flushes through the logging system + podman kill "${REGISTRY_JOB}" + podman kill "${STORAGE_JOB}" + podman kill "${PROXY_JOB}" +} +trap clean_before_exit EXIT # let the registry run for a few seconds -sleep 5 +REGISTRY_IP=$(podman inspect --format "{{ .NetworkSettings.IPAddress }}" "${REGISTRY_JOB}") +echo -e "\\033[32m---> Waitting for ${REGISTRY_IP}:5000\\033[0m" +wait-for-port --host="${REGISTRY_IP}" 5000 +echo -e "\\033[32m---> S3 service ${REGISTRY_IP}:5000 ready...\\033[0m" + +# proxy job +PROXY_JOB=$(podman run -d \ + -p 15555:8080 \ + -e DRYCC_REGISTRY_HOST="${REGISTRY_IP}:5000" \ + -e DRYCC_REGISTRY_USERNAME=admin \ + -e DRYCC_REGISTRY_PASSWORD=admin \ + "$1" start-proxy) + +# let the registry proxy run for a few seconds +REGISTRY_PROXY_IP=$(podman inspect --format "{{ .NetworkSettings.IPAddress }}" "${PROXY_JOB}") +echo -e "\\033[32m---> Waitting for ${REGISTRY_PROXY_IP}:8080\\033[0m" +wait-for-port --host="${REGISTRY_PROXY_IP}" 8080 +echo -e "\\033[32m---> S3 service ${REGISTRY_PROXY_IP}:8080 ready...\\033[0m" + # check that the registry is still up -docker logs "${JOB}" -docker ps -q --no-trunc=true | grep "${JOB}" -docker rm -f "${JOB}" "${MINIO_JOB}" +http_status_code=$(curl -X GET -s -o /dev/null -w "%{http_code}" "http://${REGISTRY_PROXY_IP}:8080/v2/") +if [ "$http_status_code" != "200" ]; then + echo "Expected http status code: 200, actual: ${http_status_code}" + exit 1 +fi + +http_status_code=$(curl -X POST -s -o /dev/null -w "%{http_code}" "http://${REGISTRY_PROXY_IP}:8080/v2/") +if [ "$http_status_code" != "403" ]; then + echo "Expected http status code: 403, actual: ${http_status_code}" + exit 1 +fi + +echo -e "\\033[32m---> All test success...\\033[0m" \ No newline at end of file diff --git a/includes.mk b/includes.mk index 5bc8456..4634e38 100644 --- a/includes.mk +++ b/includes.mk @@ -1,6 +1,6 @@ -check-docker: - @if [ -z $$(which docker) ]; then \ - echo "Missing \`docker\` client which is required for development"; \ +check-podman: + @if [ -z $$(which podman) ]; then \ + echo "Missing \`podman\` client which is required for development"; \ exit 2; \ fi diff --git a/main.go b/main.go index 407a145..27b534c 100644 --- a/main.go +++ b/main.go @@ -1,56 +1,80 @@ package main import ( - "fmt" - "io/ioutil" "log" + "net" + "net/url" "os" "os/exec" + "strings" ) const ( - registryBinary = "/bin/registry" - registryConfig = "/etc/docker/registry/config.yml" - minioHostEnvVar = "DRYCC_MINIO_SERVICE_HOST" - minioPortEnvVar = "DRYCC_MINIO_SERVICE_PORT" - command = "serve" + registryBinary = "/opt/drycc/registry/bin/registry" + registryHtpasswd = "/opt/drycc/registry/etc/htpasswd" + registryConfigEnvVar = "DRYCC_REGISTRY_CONFIG" + registryRedirectEnvVar = "DRYCC_REGISTRY_REDIRECT" + storageBucketEnvVar = "DRYCC_STORAGE_BUCKET" + storageEndpointEnvVar = "DRYCC_STORAGE_ENDPOINT" + storageAccesskeyEnvVar = "DRYCC_STORAGE_ACCESSKEY" + storageSecretkeyEnvVar = "DRYCC_STORAGE_SECRETKEY" + storagePathStyleEnvVar = "DRYCC_STORAGE_PATH_STYLE" + defaultCommand = "serve" ) func main() { log.Println("INFO: Starting registry...") - mHost := os.Getenv(minioHostEnvVar) - mPort := os.Getenv(minioPortEnvVar) os.Setenv("REGISTRY_STORAGE", "s3") - os.Setenv("REGISTRY_STORAGE_S3_BACKEND", "minio") - os.Setenv("REGISTRY_STORAGE_S3_REGIONENDPOINT", fmt.Sprintf("http://%s:%s", mHost, mPort)) + mEndpoint := os.Getenv(storageEndpointEnvVar) + os.Setenv("REGISTRY_STORAGE_S3_REGIONENDPOINT", mEndpoint) - if accesskey, err := ioutil.ReadFile("/var/run/secrets/drycc/objectstore/creds/accesskey"); err != nil { - log.Fatal(err) - } else { - os.Setenv("REGISTRY_STORAGE_S3_ACCESSKEY", string(accesskey)) + region := "us-east-1" //region is required in distribution + if endpointURL, err := url.Parse(mEndpoint); err == nil { + if endpointURL.Hostname() != "" && net.ParseIP(endpointURL.Hostname()) == nil { + region = strings.Split(endpointURL.Hostname(), ".")[0] + } } + os.Setenv("REGISTRY_STORAGE_S3_REGION", region) - if secretkey, err := ioutil.ReadFile("/var/run/secrets/drycc/objectstore/creds/secretkey"); err != nil { - log.Fatal(err) - } else { - os.Setenv("REGISTRY_STORAGE_S3_SECRETKEY", string(secretkey)) + os.Setenv("REGISTRY_STORAGE_S3_ACCESSKEY", os.Getenv(storageAccesskeyEnvVar)) + os.Setenv("REGISTRY_STORAGE_S3_SECRETKEY", os.Getenv(storageSecretkeyEnvVar)) + os.Setenv("REGISTRY_STORAGE_S3_BUCKET", os.Getenv(storageBucketEnvVar)) + + if os.Getenv(storagePathStyleEnvVar) == "true" { + os.Setenv("REGISTRY_STORAGE_S3_FORCEPATHSTYLE", "true") } - if bucket, err := ioutil.ReadFile("/var/run/secrets/drycc/objectstore/creds/registry-bucket"); err != nil { - log.Fatal(err) + + if os.Getenv(registryRedirectEnvVar) == "true" { + os.Setenv("REGISTRY_STORAGE_REDIRECT_DISABLE", "false") } else { - os.Setenv("REGISTRY_STORAGE_S3_BUCKET", string(bucket)) + os.Setenv("REGISTRY_STORAGE_REDIRECT_DISABLE", "true") } - os.Setenv("REGISTRY_STORAGE_S3_REGION", "us-east-1") + // set default env + os.Setenv("REGISTRY_STORAGE_S3_V4AUTH", "true") + os.Setenv("REGISTRY_STORAGE_S3_SECURE", "false") + os.Setenv("REGISTRY_STORAGE_S3_SKIPVERIFY", "true") + os.Setenv("REGISTRY_STORAGE_DELETE_ENABLED", "true") + os.Setenv("REGISTRY_VALIDATION_DISABLED", "true") + os.Setenv("REGISTRY_STORAGE_S3_ROOTDIRECTORY", "/registry") - // run /bin/create_bucket - cmd := exec.Command("/bin/create_bucket") + // run /bin/init-registry + os.Setenv("REGISTRY_AUTH", "htpasswd") + os.Setenv("REGISTRY_AUTH_HTPASSWD_REALM", "basic-realm") + os.Setenv("REGISTRY_AUTH_HTPASSWD_PATH", registryHtpasswd) + cmd := exec.Command("/bin/init-registry") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { log.Fatal("Error creating the registry bucket: ", err) } + // avoid conflicts with env variables + os.Unsetenv("REGISTRY_VERSION") + if len(os.Args) > 1 { + cmd = exec.Command(registryBinary, os.Args[1:]...) + } else { + cmd = exec.Command(registryBinary, defaultCommand, os.Getenv(registryConfigEnvVar)) + } - cmd = exec.Command(registryBinary, command, registryConfig) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { @@ -58,11 +82,3 @@ func main() { } log.Println("INFO: registry started.") } - -func getenv(name, dfault string) string { - value := os.Getenv(name) - if value == "" { - value = dfault - } - return value -} diff --git a/rootfs/bin/create_bucket b/rootfs/bin/create_bucket deleted file mode 100755 index 196a744..0000000 --- a/rootfs/bin/create_bucket +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash - -set -e - -# shellcheck disable=SC1091 -source /bin/normalize_storage - -has_bucket(){ - mc ls minio -json|jq -r '.key'|grep -w "${MINIO_BUCKET}" -} - -if [ -z "$(has_bucket)" ] ;then - mc mb minio/"${MINIO_BUCKET}" - if [ -z "$(has_bucket)" ] ;then - echo "create bucket ${MINIO_BUCKET} error" - exit 1 - fi -fi -echo "create bucket ${MINIO_BUCKET} success" diff --git a/rootfs/bin/init-registry b/rootfs/bin/init-registry new file mode 100755 index 0000000..4d05fc8 --- /dev/null +++ b/rootfs/bin/init-registry @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +set -e + + +mkdir -p ~/.config/rclone +touch ~/.config/rclone/rclone.conf +rclone config create storage s3 \ + provider=Other \ + access_key_id="${DRYCC_STORAGE_ACCESSKEY}" \ + secret_access_key="${DRYCC_STORAGE_SECRETKEY}" \ + endpoint="${DRYCC_STORAGE_ENDPOINT}" \ + force_path_style="${DRYCC_STORAGE_PATH_STYLE:-true}" --no-output + +if ! rclone lsd storage: > /dev/null 2>&1; then + sleep 9s + echo "waiting for object storage to become ready..." +fi + +rclone mkdir "storage:${DRYCC_STORAGE_BUCKET}" + +htpasswd -Bbn "${DRYCC_REGISTRY_USERNAME}" "${DRYCC_REGISTRY_PASSWORD}" > "${REGISTRY_AUTH_HTPASSWD_PATH}" +echo "create ${REGISTRY_AUTH_HTPASSWD_PATH} success" diff --git a/rootfs/bin/normalize_storage b/rootfs/bin/normalize_storage deleted file mode 100755 index fef58d8..0000000 --- a/rootfs/bin/normalize_storage +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env sh -BUCKET_FILE="/var/run/secrets/drycc/objectstore/creds/registry-bucket" -ACCESS_KEY_FILE="/var/run/secrets/drycc/objectstore/creds/accesskey" -SECRET_KEY_FILE="/var/run/secrets/drycc/objectstore/creds/secretkey" - -if [ -f $BUCKET_FILE ]; then - MINIO_BUCKET=$(cat "$BUCKET_FILE") - export MINIO_BUCKET -fi -if [ -f $ACCESS_KEY_FILE ]; then - MINIO_ACCESS_KEY=$(cat "$ACCESS_KEY_FILE") - export MINIO_ACCESS_KEY -fi -if [ -f $SECRET_KEY_FILE ]; then - MINIO_SECRET_KEY=$(cat "$SECRET_KEY_FILE") - export MINIO_SECRET_KEY -fi - -export MINIO_ENDPOINT=http://"${DRYCC_MINIO_SERVICE_HOST}:${DRYCC_MINIO_SERVICE_PORT}" - -mc config host add minio "${MINIO_ENDPOINT}" "${MINIO_ACCESS_KEY}" "${MINIO_SECRET_KEY}" diff --git a/rootfs/bin/start-proxy b/rootfs/bin/start-proxy new file mode 100755 index 0000000..5354551 --- /dev/null +++ b/rootfs/bin/start-proxy @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +REGISTRY_HOST=${DRYCC_REGISTRY_HOST:?no host} +AUTHORIZATION=$(echo -ne "${DRYCC_REGISTRY_USERNAME:? no username}":"${DRYCC_REGISTRY_PASSWORD:? no password}" | base64 -w 0) + +cat /opt/drycc/nginx/conf/registry.conf.tpl > /opt/drycc/nginx/conf/registry.conf +sed -i "s#%REGISTRY_HOST%#${REGISTRY_HOST}#g" /opt/drycc/nginx/conf/registry.conf +sed -i "s#%AUTHORIZATION%#${AUTHORIZATION}#g" /opt/drycc/nginx/conf/registry.conf + +# wait for registry to come online +while ! curl -sS "$REGISTRY_HOST" &>/dev/null; do + echo "waiting for the registry (%s) to come online..." + echo "$REGISTRY_HOST" + sleep 1 +done + +echo "starting registry-proxy..." +exec nginx -g "daemon off;" diff --git a/rootfs/config-example.yml b/rootfs/config-example.yml new file mode 100644 index 0000000..a55566c --- /dev/null +++ b/rootfs/config-example.yml @@ -0,0 +1,23 @@ +version: 0.1 +log: + fields: + service: registry +storage: + cache: + blobdescriptor: inmemory + filesystem: + rootdirectory: /var/lib/registry +http: + addr: :5000 + debug: + addr: :9000 + prometheus: + enabled: true + path: /metrics + headers: + X-Content-Type-Options: [nosniff] +health: + storagedriver: + enabled: true + interval: 10s + threshold: 3 diff --git a/rootfs/etc/docker/registry/config.yml b/rootfs/etc/docker/registry/config.yml deleted file mode 100644 index b5700e1..0000000 --- a/rootfs/etc/docker/registry/config.yml +++ /dev/null @@ -1,18 +0,0 @@ -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] -health: - storagedriver: - enabled: true - interval: 10s - threshold: 3 diff --git a/rootfs/opt/drycc/nginx/conf/nginx.conf b/rootfs/opt/drycc/nginx/conf/nginx.conf new file mode 100644 index 0000000..bd3f31d --- /dev/null +++ b/rootfs/opt/drycc/nginx/conf/nginx.conf @@ -0,0 +1,22 @@ +worker_processes 1; + +error_log /dev/stderr warn; +pid /opt/drycc/nginx/logs/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /opt/drycc/nginx/conf/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /dev/stdout main; + sendfile on; + keepalive_timeout 65; + include /opt/drycc/nginx/conf/registry.conf; +} diff --git a/rootfs/opt/drycc/nginx/conf/registry.conf.tpl b/rootfs/opt/drycc/nginx/conf/registry.conf.tpl new file mode 100644 index 0000000..627f2f2 --- /dev/null +++ b/rootfs/opt/drycc/nginx/conf/registry.conf.tpl @@ -0,0 +1,24 @@ +upstream container-registry { + server %REGISTRY_HOST%; +} + +server { + listen 8080; + server_name localhost; + # disable any limits to avoid HTTP 413 for large image uploads + client_max_body_size 0; + # required to avoid HTTP 411: see Issue #1486 (https://github.com/moby/moby/issues/1486) + chunked_transfer_encoding on; + location / { + proxy_pass http://container-registry; + proxy_set_header Host $http_host; # required for container client's sake + proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 900; + proxy_set_header Authorization "Basic %AUTHORIZATION%"; + limit_except GET HEAD OPTIONS { + deny all; + } + } +} \ No newline at end of file diff --git a/versioning.mk b/versioning.mk index 2bfd999..8b30958 100644 --- a/versioning.mk +++ b/versioning.mk @@ -11,13 +11,13 @@ info: @echo "Immutable tag: ${IMAGE}" @echo "Mutable tag: ${MUTABLE_IMAGE}" -.PHONY: docker-push -docker-push: docker-immutable-push docker-mutable-push +.PHONY: podman-push +podman-push: podman-immutable-push podman-mutable-push -.PHONY: docker-immutable-push -docker-immutable-push: - docker push ${IMAGE} +.PHONY: podman-immutable-push +podman-immutable-push: + podman push ${IMAGE} -.PHONY: docker-mutable-push -docker-mutable-push: - docker push ${MUTABLE_IMAGE} +.PHONY: podman-mutable-push +podman-mutable-push: + podman push ${MUTABLE_IMAGE}