Prepare prototype for deployment (#20)

Closes #9

Signed-off-by: Sergio Castaño Arteaga <tegioz@icloud.com>
This commit is contained in:
Sergio C. Arteaga 2020-01-21 10:08:52 +01:00 committed by GitHub
parent e0a1ab3d07
commit c3489a6ff6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 262 additions and 15 deletions

2
.dockerignore Normal file
View File

@ -0,0 +1,2 @@
.git
web/node_modules

5
chart/.helmignore Normal file
View File

@ -0,0 +1,5 @@
.DS_Store
.git/
.gitignore
*.swp
.vscode/

6
chart/Chart.yaml Normal file
View File

@ -0,0 +1,6 @@
apiVersion: v2
name: hub
description: Hub Helm chart
type: application
version: 0.1.0
appVersion: 0.1.0

View File

@ -0,0 +1,52 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "chart.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "chart.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "chart.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Common labels
*/}}
{{- define "chart.labels" -}}
helm.sh/chart: {{ include "chart.chart" . }}
{{ include "chart.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end -}}
{{/*
Selector labels
*/}}
{{- define "chart.selectorLabels" -}}
app.kubernetes.io/name: {{ include "chart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}

View File

@ -0,0 +1,47 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: hub
labels:
app.kubernetes.io/component: hub
{{- include "chart.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.hub.deploy.replicaCount }}
selector:
matchLabels:
app.kubernetes.io/component: hub
{{- include "chart.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
app.kubernetes.io/component: hub
{{- include "chart.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: hub
image: "{{ .Values.hub.deploy.image.repository }}"
imagePullPolicy: {{ .Values.pullPolicy }}
volumeMounts:
- name: hub-config
mountPath: "/home/hub/.cfg"
readOnly: true
ports:
- name: http
containerPort: 8000
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
volumes:
- name: hub-config
secret:
secretName: hub-config

View File

@ -0,0 +1,21 @@
{{- if .Values.hub.ingress.enabled -}}
{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: hub
labels:
app.kubernetes.io/component: hub
{{- include "chart.labels" . | nindent 4 }}
{{- with .Values.hub.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
backend:
serviceName: hub
servicePort: {{ .Values.hub.service.port }}
{{- end }}

View File

@ -0,0 +1,16 @@
apiVersion: v1
kind: Secret
metadata:
name: hub-config
type: Opaque
stringData:
hub.yaml: |-
log:
level: {{ .Values.log.level }}
pretty: {{ .Values.log.pretty }}
db:
url: {{ .Values.db.url }}
server:
addr: 0.0.0.0:8000
shutdownTimeout: 30s
webBuildPath: ./web

View File

@ -0,0 +1,17 @@
apiVersion: v1
kind: Service
metadata:
name: hub
labels:
app.kubernetes.io/component: hub
{{- include "chart.labels" . | nindent 4 }}
spec:
type: {{ .Values.hub.service.type }}
ports:
- port: {{ .Values.hub.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/component: hub
{{- include "chart.selectorLabels" . | nindent 4 }}

24
chart/values.yaml Normal file
View File

@ -0,0 +1,24 @@
nameOverride: ""
fullnameOverride: ""
imagePullSecrets: []
pullPolicy: IfNotPresent
db:
url: postgres://postgres@192.168.64.1:5432/hub
log:
level: info
pretty: false
hub:
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
service:
type: ClusterIP
port: 80
deploy:
replicaCount: 1
image:
repository: tegioz/hub

View File

@ -0,0 +1,15 @@
# Build chart-tracker
FROM golang:1.13-alpine AS builder
WORKDIR /go/src/github.com/tegioz/hub
COPY go.* ./
COPY cmd/chart-tracker cmd/chart-tracker
COPY internal internal
RUN cd cmd/chart-tracker && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /chart-tracker .
# Final stage
FROM alpine:latest
RUN apk --no-cache add ca-certificates && addgroup -S chart-tracker && adduser -S chart-tracker -G chart-tracker
USER chart-tracker
WORKDIR /home/chart-tracker
COPY --from=builder /chart-tracker ./
CMD ["./chart-tracker"]

View File

@ -20,7 +20,7 @@ func main() {
}
fields := map[string]interface{}{
"cmd": "chart-tracker",
"repo": cfg.GetString("tracker.repo-name"),
"repo": cfg.GetString("tracker.repoName"),
}
if err := util.SetupLogger(cfg, fields); err != nil {
log.Fatal().Err(err).Msg("Logger setup failed")
@ -43,7 +43,7 @@ func main() {
log.Fatal().Err(err).Msg("Database setup failed")
}
hubApi := hub.New(db)
cr, err := hubApi.GetChartRepositoryByName(ctx, cfg.GetString("tracker.repo-name"))
cr, err := hubApi.GetChartRepositoryByName(ctx, cfg.GetString("tracker.repoName"))
if err != nil {
log.Fatal().Err(err).Msg("Error getting chart repository")
}
@ -56,7 +56,7 @@ func main() {
}
wg.Add(1)
go dispatcher.run(ctx, &wg)
for i := 0; i < cfg.GetInt("tracker.num-workers"); i++ {
for i := 0; i < cfg.GetInt("tracker.numWorkers"); i++ {
w := newWorker(ctx, i, hubApi, cr)
wg.Add(1)
go w.run(&wg, dispatcher.Queue)

24
cmd/hub/Dockerfile Normal file
View File

@ -0,0 +1,24 @@
# Build backend
FROM golang:1.13-alpine AS backend-builder
WORKDIR /go/src/github.com/tegioz/hub
COPY go.* ./
COPY cmd/hub cmd/hub
COPY internal internal
RUN cd cmd/hub && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /hub .
# Build frontend
FROM node:13-alpine AS frontend-builder
WORKDIR /web
COPY web .
RUN yarn install
RUN yarn build
# Final stage
FROM alpine:latest
RUN apk --no-cache add ca-certificates && addgroup -S hub && adduser -S hub -G hub
USER hub
WORKDIR /home/hub
COPY --from=backend-builder /hub ./
COPY --from=frontend-builder /web/build ./web
CMD ["./hub"]
EXPOSE 8000

View File

@ -40,7 +40,7 @@ func (h *handlers) setupRouter() {
r.GET("/api/v1/package/:package_id/:version", h.getPackageVersion)
// Static files
staticFilesPath := path.Join(h.cfg.GetString("server.web-build-path"), "static")
staticFilesPath := path.Join(h.cfg.GetString("server.webBuildPath"), "static")
r.ServeFiles("/static/*filepath", http.Dir(staticFilesPath))
r.NotFound = h.serveFile("index.html")
@ -86,7 +86,7 @@ func (h *handlers) getPackageVersion(w http.ResponseWriter, r *http.Request, ps
func (h *handlers) serveFile(name string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, path.Join(h.cfg.GetString("server.web-build-path"), name))
http.ServeFile(w, r, path.Join(h.cfg.GetString("server.webBuildPath"), name))
})
}

View File

@ -52,7 +52,7 @@ func main() {
signal.Notify(shutdown, os.Interrupt, syscall.SIGTERM)
<-shutdown
log.Info().Msg("Hub server shutting down..")
ctx, cancel := context.WithTimeout(context.Background(), cfg.GetDuration("server.shutdown-timeout"))
ctx, cancel := context.WithTimeout(context.Background(), cfg.GetDuration("server.shutdownTimeout"))
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatal().Err(err).Msg("Hub server shutdown failed")

View File

@ -4,5 +4,5 @@ log:
db:
url: postgres://postgres@localhost:5432/hub
tracker:
num-workers: 100
repo-name: helm/stable
numWorkers: 100
repoName: helm/stable

View File

@ -5,5 +5,5 @@ db:
url: postgres://postgres@localhost:5432/hub
server:
addr: localhost:8000
shutdown-timeout: 1m
web-build-path: ../../web/build
shutdownTimeout: 1m
webBuildPath: ../../web/build

View File

@ -0,0 +1,14 @@
# Build tern
FROM golang:1.13-alpine AS builder
RUN apk --no-cache add git
RUN go get -u github.com/jackc/tern
# Final stage
FROM alpine:latest
RUN apk --no-cache add ca-certificates && addgroup -S db-migrator && adduser -S db-migrator -G db-migrator
USER db-migrator
WORKDIR /home/db-migrator
COPY --from=builder /go/bin/tern .
COPY database/migrations .
COPY configs/tern.conf tern.conf
CMD ["./tern", "migrate"]

View File

@ -14,7 +14,6 @@ func SetupConfig(cmd string) (*viper.Viper, error) {
// Config file
cfg.SetConfigName(cmd)
cfg.AddConfigPath("$HOME/.cfg")
cfg.AddConfigPath("../../configs")
if err := cfg.ReadInConfig(); err != nil {
log.Fatal().Err(err)
}

5
scripts/docker-build.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
docker build -f cmd/hub/Dockerfile -t tegioz/hub .
docker build -f cmd/chart-tracker/Dockerfile -t tegioz/chart-tracker .
docker build -f database/migrations/Dockerfile -t tegioz/db-migrator .

View File

@ -1,5 +1,5 @@
{
"name": "helm-hub",
"name": "hub",
"version": "0.1.0",
"private": true,
"dependencies": {

View File

@ -1,11 +1,11 @@
import { PackagesList, PackageDetail } from '../types';
import fetchApi, { } from '../utils/fetchApi';
import fetchApi, { } from '../utils/fetchApi';
const API_ROUTE = 'http://localhost:8000/api/v1/';
const API_ROUTE = '/api/v1';
const API = {
getPackage: (id?: string, version?: string): Promise<PackageDetail> => {
return fetchApi(`${API_ROUTE}package/${id}${version ? `/${version}` : ''}`);
return fetchApi(`${API_ROUTE}/package/${id}${version ? `/${version}` : ''}`);
},
searchPackages: (q: string): Promise<PackagesList> => {
return fetchApi(`${API_ROUTE}/search?q=${q}`);