mirror of
https://github.com/replicatedhq/ttl.sh.git
synced 2026-02-14 16:59:51 +00:00
36
README.md
36
README.md
@@ -1,3 +1,5 @@
|
||||
[](https://replicated.okteto.dev/deploy?repository=https://github.com/replicatedhq/ttl.sh&branch=main)
|
||||
|
||||
# ttl.sh
|
||||
|
||||
## An ephemeral container registry for CI workflows.
|
||||
@@ -6,3 +8,37 @@
|
||||
|
||||
ttl.sh is an anonymous, expiring Docker container registry using the official Docker Registry image. This is a set of tools and configurations that can be used to deploy the registry without authentication, but with self-expiring images.
|
||||
|
||||
# Development
|
||||
|
||||
Development for the services in this project is done through [Okteto](https://replicated.okteto.dev).
|
||||
|
||||
## Setup
|
||||
|
||||
1. Install the Okteto CLI (`brew install okteto`)
|
||||
2. Setup Okteto CLI (`okteto context use https://replicated.okteto.dev`)
|
||||
3. Setup Okteto context in kubectl (`okteto context update-kubeconfig`)
|
||||
4. Deploy your current branch. (from the ttl.sh root directory: `okteto pipeline deploy`)
|
||||
|
||||
## Debugging
|
||||
|
||||
Okteto is utilized for debugging. New build targets have been added to allow building and running each service in debug mode.
|
||||
|
||||
1. Replace the default container in your Okteto environment with a development container.
|
||||
1. From the root directory: `okteto up` or `okteto up <service name>`
|
||||
2. Run the build targets for the desired service:
|
||||
1. ttl-hooks: `make deps build hooks`
|
||||
2. ttl-reaper: `make deps build reap`
|
||||
3. Stop development and go back to the default container.
|
||||
1. From the root directory: `okteto down` or `okteto down <service name>`
|
||||
|
||||
## Example workflows
|
||||
|
||||
### Switching branches or rebasing
|
||||
|
||||
1. `git checkout my-new-branch`
|
||||
2. `okteto pipeline deploy`
|
||||
3. (make code changes)
|
||||
4. `okteto up`
|
||||
5. (test changes, find they don't work, make more changes)...
|
||||
6. `okteto down`
|
||||
7. (commit code, and be happy)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { tryParsePutTagRequest, handleTagManifestRequest } from "./tag_manifest";
|
||||
|
||||
if (typeof addEventListener === 'function') {
|
||||
addEventListener('fetch', (e: Event): void => {
|
||||
// work around as strict typescript check doesn't allow e to be of type FetchEvent
|
||||
|
||||
56
hooks/.stignore
Normal file
56
hooks/.stignore
Normal file
@@ -0,0 +1,56 @@
|
||||
.git
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
jspm_packages
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
FROM node:10 as deps
|
||||
|
||||
ADD ./package.json /src/package.json
|
||||
ADD ./Makefile /src/Makefile
|
||||
ADD . /src
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
FROM node:10 as deps
|
||||
|
||||
ADD ./package.json /src/package.json
|
||||
ADD ./Makefile /src/Makefile
|
||||
ADD . /src
|
||||
|
||||
@@ -11,7 +11,7 @@ deps:
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
`npm bin`/tslint --project ./tsconfig.json --fix
|
||||
npx tslint --project ./tsconfig.json --fix
|
||||
|
||||
.PHONY: test
|
||||
test: build
|
||||
@@ -19,10 +19,10 @@ test: build
|
||||
|
||||
.PHONY: build
|
||||
build: prebuild
|
||||
`npm bin`/tsc
|
||||
npx tsc
|
||||
|
||||
.PHONY: run
|
||||
run:
|
||||
.PHONY: hooks
|
||||
hooks:
|
||||
node --no-deprecation ./build/server.js hooks
|
||||
|
||||
.PHONY: reap
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import * as util from "util";
|
||||
import { Server } from "../server/server";
|
||||
import { logger } from "../logger";
|
||||
import { param } from "../util";
|
||||
|
||||
exports.name = "hooks";
|
||||
exports.describe = "Start and run the hook api server";
|
||||
@@ -17,7 +16,7 @@ exports.handler = async (argv) => {
|
||||
};
|
||||
|
||||
async function main(argv): Promise<any> {
|
||||
process.on('SIGTERM', function onSigterm () {
|
||||
process.on("SIGTERM", function onSigterm() {
|
||||
logger.info(`Got SIGTERM, cleaning up`);
|
||||
process.exit();
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ import * as redis from "redis";
|
||||
import { promisify } from "util";
|
||||
import * as rp from "request-promise";
|
||||
|
||||
const registryUrl = process.env["REGISTRY_URL"] || "https://ttl.sh";
|
||||
const client = redis.createClient({url: process.env["REDISCLOUD_URL"]});
|
||||
const smembersAsync = promisify(client.smembers).bind(client);
|
||||
const sremAsync = promisify(client.srem).bind(client);
|
||||
@@ -25,7 +26,7 @@ exports.handler = async (argv) => {
|
||||
};
|
||||
|
||||
async function main(argv): Promise<any> {
|
||||
process.on('SIGTERM', function onSigterm () {
|
||||
process.on("SIGTERM", function onSigterm() {
|
||||
logger.info(`Got SIGTERM, cleaning up`);
|
||||
process.exit();
|
||||
});
|
||||
@@ -73,17 +74,17 @@ async function reapExpiredImages() {
|
||||
|
||||
const imageAndTag = image.split(":");
|
||||
const headers = {
|
||||
"Accept": "application/vnd.docker.distribution.manifest.v2+json",
|
||||
Accept: "application/vnd.docker.distribution.manifest.v2+json",
|
||||
};
|
||||
|
||||
// Get the manifest from the tag
|
||||
const getOptions = {
|
||||
method: "HEAD",
|
||||
uri: `https://ttl.sh/v2/${imageAndTag[0]}/manifests/${imageAndTag[1]}`,
|
||||
uri: `${registryUrl}/v2/${imageAndTag[0]}/manifests/${imageAndTag[1]}`,
|
||||
headers,
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
}
|
||||
};
|
||||
const getResponse = await rp(getOptions);
|
||||
|
||||
if (getResponse.statusCode == 404) {
|
||||
@@ -92,7 +93,7 @@ async function reapExpiredImages() {
|
||||
continue;
|
||||
}
|
||||
|
||||
const deleteURI = `https://ttl.sh/v2/${imageAndTag[0]}/manifests/${getResponse.headers.etag.replace(/"/g,"")}`;
|
||||
const deleteURI = `${registryUrl}/v2/${imageAndTag[0]}/manifests/${getResponse.headers.etag.replace(/"/g, "")}`;
|
||||
|
||||
// Remove from the registry
|
||||
const options = {
|
||||
@@ -101,7 +102,7 @@ async function reapExpiredImages() {
|
||||
headers,
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
}
|
||||
};
|
||||
|
||||
await rp(options);
|
||||
|
||||
|
||||
@@ -57,10 +57,10 @@ export class HookAPI {
|
||||
console.log(`parsing tag ${tag}`);
|
||||
let expiresIn = durationfromTag(tag);
|
||||
if (expiresIn <= 0) {
|
||||
expiresIn = defaultDuration
|
||||
expiresIn = defaultDuration;
|
||||
}
|
||||
if (expiresIn > maxDuration) {
|
||||
expiresIn = maxDuration
|
||||
expiresIn = maxDuration;
|
||||
}
|
||||
|
||||
await saddAsync("current.images", imageWithTag);
|
||||
|
||||
@@ -13,7 +13,7 @@ function initLogger(): any {
|
||||
logger.level = process.env["LOG_LEVEL"] || "warn";
|
||||
return logger;
|
||||
} else {
|
||||
const logger = pino(logOptions)
|
||||
const logger = pino(logOptions);
|
||||
logger.level = process.env["LOG_LEVEL"] || "warn";
|
||||
return logger;
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ export const preRequest = (req: express.Request, reqId: string) => {
|
||||
export const requestId = (req: express.Request, handlerName: string) => {
|
||||
const id = `${handlerName}:${uuid.v4().replace("-", "").substring(0, 8)}`;
|
||||
|
||||
const clientID: string = <string> req.headers["x-request-uuid"];
|
||||
const clientID: string = req.headers["x-request-uuid"] as string;
|
||||
|
||||
if (clientID) {
|
||||
return `${id}.${clientID.substring(0, 8)}`;
|
||||
|
||||
@@ -21,7 +21,7 @@ if (port == null || port == "") {
|
||||
debug: false,
|
||||
logger: {
|
||||
level: "warn",
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
export class Server extends ServerLoader {
|
||||
|
||||
3
kustomize/base/kustomization.yaml
Normal file
3
kustomize/base/kustomization.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources: []
|
||||
62
kustomize/overlays/dev/hooks.yaml
Normal file
62
kustomize/overlays/dev/hooks.yaml
Normal file
@@ -0,0 +1,62 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: ttl-hooks
|
||||
labels:
|
||||
app: ttl-hooks
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: ttl-hooks
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: ttl-hooks
|
||||
spec:
|
||||
restartPolicy: Always
|
||||
initContainers:
|
||||
- name: wait-for-registry
|
||||
image: quay.io/curl/curl:latest
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
until curl -s -o /dev/null -w "%{http_code}" ttl-registry:5000/v2/; do
|
||||
echo "Waiting for Docker Registry to be ready..."
|
||||
sleep 2
|
||||
done
|
||||
- name: wait-for-redis
|
||||
image: redis:latest
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
until redis-cli -h ttl-redis -p 6379 ping | grep "PONG"; do
|
||||
echo "Waiting for Redis to be ready..."
|
||||
sleep 2
|
||||
done
|
||||
containers:
|
||||
- name: ttl-hooks
|
||||
image: ttl-hooks
|
||||
ports:
|
||||
- containerPort: 8000
|
||||
env:
|
||||
- name: REDISCLOUD_URL
|
||||
value: redis://ttl-redis:6379
|
||||
- name: HOOK_TOKEN
|
||||
value: dev-hook-token
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: ttl-hooks
|
||||
labels:
|
||||
app: ttl-hooks
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8000
|
||||
targetPort: 8000
|
||||
selector:
|
||||
app: ttl-hooks
|
||||
8
kustomize/overlays/dev/kustomization.yaml
Normal file
8
kustomize/overlays/dev/kustomization.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- ../../base
|
||||
- ./hooks.yaml
|
||||
- ./reaper.yaml
|
||||
- ./redis.yaml
|
||||
- ./registry.yaml
|
||||
62
kustomize/overlays/dev/reaper.yaml
Normal file
62
kustomize/overlays/dev/reaper.yaml
Normal file
@@ -0,0 +1,62 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: ttl-reaper
|
||||
labels:
|
||||
app: ttl-reaper
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: ttl-reaper
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: ttl-reaper
|
||||
spec:
|
||||
restartPolicy: Always
|
||||
initContainers:
|
||||
- name: wait-for-registry
|
||||
image: quay.io/curl/curl:latest
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
until curl -s -o /dev/null -w "%{http_code}" ttl-registry:5000/v2/; do
|
||||
echo "Waiting for Docker Registry to be ready..."
|
||||
sleep 2
|
||||
done
|
||||
- name: wait-for-redis
|
||||
image: redis:latest
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
until redis-cli -h ttl-redis -p 6379 ping | grep "PONG"; do
|
||||
echo "Waiting for Redis to be ready..."
|
||||
sleep 2
|
||||
done
|
||||
containers:
|
||||
- name: ttl-reaper
|
||||
image: ttl-reaper
|
||||
ports:
|
||||
- containerPort: 8000
|
||||
env:
|
||||
- name: REGISTRY_URL
|
||||
value: http://ttl-registry:5000
|
||||
- name: REDISCLOUD_URL
|
||||
value: redis://ttl-redis:6379
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: ttl-reaper
|
||||
labels:
|
||||
app: ttl-reaper
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8000
|
||||
targetPort: 8000
|
||||
selector:
|
||||
app: ttl-reaper
|
||||
50
kustomize/overlays/dev/redis.yaml
Normal file
50
kustomize/overlays/dev/redis.yaml
Normal file
@@ -0,0 +1,50 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: ttl-redis
|
||||
labels:
|
||||
app: ttl-redis
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: ttl-redis
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: ttl-redis
|
||||
spec:
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:latest
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
volumeMounts:
|
||||
- name: redis-data
|
||||
mountPath: /data
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- redis-cli
|
||||
- ping
|
||||
initialDelaySeconds: 20
|
||||
timeoutSeconds: 5
|
||||
periodSeconds: 3
|
||||
volumes:
|
||||
- name: redis-data
|
||||
emptyDir: {}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: ttl-redis
|
||||
labels:
|
||||
app: ttl-redis
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 6379
|
||||
targetPort: 6379
|
||||
selector:
|
||||
app: ttl-redis
|
||||
90
kustomize/overlays/dev/registry.yaml
Normal file
90
kustomize/overlays/dev/registry.yaml
Normal file
@@ -0,0 +1,90 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: ttl-registry
|
||||
labels:
|
||||
app: ttl-registry
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: ttl-registry
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: ttl-registry
|
||||
spec:
|
||||
containers:
|
||||
- name: ttl-registry
|
||||
image: registry:2
|
||||
ports:
|
||||
- containerPort: 5000
|
||||
volumeMounts:
|
||||
- name: registry-data
|
||||
mountPath: /var/lib/registry
|
||||
- name: registry-config
|
||||
mountPath: /etc/docker/registry/config.yml
|
||||
subPath: config.yml
|
||||
readinessProbe:
|
||||
failureThreshold: 3
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 1
|
||||
successThreshold: 2
|
||||
timeoutSeconds: 1
|
||||
httpGet:
|
||||
path: /
|
||||
port: 5000
|
||||
scheme: HTTP
|
||||
volumes:
|
||||
- name: registry-data
|
||||
emptyDir: {}
|
||||
- name: registry-config
|
||||
configMap:
|
||||
name: registry-config
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: registry-config
|
||||
labels:
|
||||
app: ttl-registry
|
||||
data:
|
||||
config.yml: |
|
||||
version: 0.1
|
||||
log:
|
||||
level: debug
|
||||
storage:
|
||||
delete:
|
||||
enabled: true
|
||||
filesystem:
|
||||
rootdirectory: /var/lib/registry
|
||||
http:
|
||||
addr: 0.0.0.0:5000
|
||||
headers:
|
||||
X-Content-Type-Options: [nosniff]
|
||||
notifications:
|
||||
endpoints:
|
||||
- name: ttl-hooks
|
||||
url: http://ttl-hooks:8000/v1/hook/registry-event
|
||||
headers:
|
||||
Authorization: ["Token dev-hook-token"]
|
||||
timeout: 200ms
|
||||
threshold: 3
|
||||
backoff: 5s
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: ttl-registry
|
||||
labels:
|
||||
app: ttl-registry
|
||||
annotations:
|
||||
dev.okteto.com/auto-ingress: "true"
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5000
|
||||
targetPort: 5000
|
||||
selector:
|
||||
app: ttl-registry
|
||||
33
okteto.yml
Normal file
33
okteto.yml
Normal file
@@ -0,0 +1,33 @@
|
||||
build:
|
||||
ttl-hooks:
|
||||
context: ./hooks
|
||||
dockerfile: ./hooks/Dockerfile.hooks
|
||||
ttl-reaper:
|
||||
context: ./hooks
|
||||
dockerfile: ./hooks/Dockerfile.reap
|
||||
|
||||
deploy:
|
||||
- cd kustomize/overlays/dev && kustomize edit set image ttl-hooks=${OKTETO_BUILD_TTL_HOOKS_IMAGE}
|
||||
- cd kustomize/overlays/dev && kustomize edit set image ttl-reaper=${OKTETO_BUILD_TTL_REAPER_IMAGE}
|
||||
|
||||
- kubectl apply -k kustomize/overlays/dev
|
||||
|
||||
dev:
|
||||
ttl-hooks:
|
||||
command: make deps build && bash || bash
|
||||
workdir: /src
|
||||
sync:
|
||||
- ./hooks:/src
|
||||
resources:
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 1Gi
|
||||
ttl-reaper:
|
||||
command: make deps build && bash || bash
|
||||
workdir: /src
|
||||
sync:
|
||||
- ./hooks:/src
|
||||
resources:
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 1Gi
|
||||
Reference in New Issue
Block a user