- add: helm chart

- add: python script for building and pushing the containers
This commit is contained in:
2025-03-17 23:59:33 -04:00
parent cf9efc9866
commit eebf5c58e0
11 changed files with 453 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

View File

@@ -0,0 +1,24 @@
apiVersion: v2
name: osirose-new
description: A Helm chart for Kubernetes
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "0.1.0"

View File

@@ -0,0 +1,62 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "osirose-new.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 "osirose-new.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 "osirose-new.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "osirose-new.labels" -}}
helm.sh/chart: {{ include "osirose-new.chart" . }}
{{ include "osirose-new.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "osirose-new.selectorLabels" -}}
app.kubernetes.io/name: {{ include "osirose-new.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "osirose-new.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "osirose-new.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,14 @@
{{- range .Values.services }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .name }}-env
data:
{{- range $key, $value := $.Values.global.env }}
{{ $key }}: "{{ $value }}"
{{- end }}
{{- range $key, $value := .env }}
{{ $key }}: "{{ $value }}"
{{- end }}
---
{{- end }}

View File

@@ -0,0 +1,33 @@
{{- range .Values.services }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .name }}
labels:
app: {{ .name }}
spec:
replicas: {{ .replicas }}
selector:
matchLabels:
app: {{ .name }}
template:
metadata:
labels:
app: {{ .name }}
spec:
containers:
- name: {{ .name }}
image: "{{ $.Values.repository }}/{{ .image }}"
ports:
- containerPort: {{ .port }}
envFrom:
- configMapRef:
name: {{ .name }}-env
volumeMounts:
- name: service-ids
mountPath: /services
volumes:
- name: service-ids
emptyDir: {}
---
{{- end }}

View File

@@ -0,0 +1,33 @@
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "osirose-new.fullname" . }}
labels:
{{- include "osirose-new.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "osirose-new.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
---
{{- end }}

View File

@@ -0,0 +1,25 @@
{{- range .Values.services }}
{{- if .ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ .name }}-ingress
labels:
app: {{ .name }}
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: {{ .ingress.hostname }}
http:
paths:
- path: {{ .ingress.path }}
pathType: Prefix
backend:
service:
name: {{ .name }}
port:
number: {{ .port }}
---
{{- end }}
{{- end }}

View File

@@ -0,0 +1,20 @@
{{- range .Values.services }}
{{- if .tcp.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ .name }}
labels:
app: {{ .name }}
spec:
type: {{ .tcp.type | default "ClusterIP" }}
ports:
- name: {{ .tcp.portName | default "tcp" }}
port: {{ .tcp.port }}
targetPort: {{ .tcp.targetPort | default .tcp.port }}
protocol: {{ .tcp.protocol | default "TCP" }}
selector:
app: {{ .name }}
{{- end }}
---
{{- end }}

View File

@@ -0,0 +1,20 @@
{{- if .Values.tests.enabled }}
{{- range .Values.tests.services }}
apiVersion: v1
kind: Pod
metadata:
name: {{ .name }}-test
annotations:
"helm.sh/hook": test
"helm.sh/hook-delete-policy": before-hook-creation
labels:
app: {{ .name }}
spec:
containers:
- name: {{ .name }}-test
image: {{ .image }}
command: {{ .testCommand }}
restartPolicy: Never
---
{{- end }}
{{- end }}

View File

@@ -0,0 +1,127 @@
repository: gitea.azgstudio.com/raven
autoscaling:
enabled: false
global:
env:
LOG_LEVEL: "info"
APP_ENV: "dev"
DATABASE_URL: "postgres://postgres:5432/osirose"
services:
- name: api-service
replicas: 1
image: api-service:latest
port: 8080
env:
SERVICE_NAME: "api-service"
tcp:
enabled: true
portName: api-service
port: 8080
targetPort: 8080
protocol: TCP
ingress:
enabled: true
hostname: game-api.azgstudio.com
path: "/"
port: 8080
- name: auth-service
replicas: 1
image: auth-service:latest
port: 50051
env:
SERVICE_NAME: "auth-service"
tcp:
enabled: true
portName: auth-service
port: 50051
targetPort: 50051
protocol: TCP
ingress:
enabled: false
- name: character-service
replicas: 1
image: character-service:latest
port: 50053
env:
SERVICE_NAME: "character-service"
tcp:
enabled: true
portName: character-service
port: 50053
targetPort: 50053
protocol: TCP
ingress:
enabled: false
- name: database-service
replicas: 1
image: database-service:latest
port: 50052
env:
SERVICE_NAME: "database-service"
tcp:
enabled: true
portName: database-service
port: 50052
targetPort: 50052
protocol: TCP
ingress:
enabled: false
- name: packet-service
replicas: 1
image: packet-service:latest
port: 29000
env:
SERVICE_NAME: "packet-service"
tcp:
enabled: true
portName: game-packet-service
port: 29000
targetPort: 29000
protocol: TCP
ingress:
enabled: false
- name: session-service
replicas: 1
image: session-service:latest
port: 50055
env:
SERVICE_NAME: "session-service"
tcp:
enabled: true
portName: session-service
port: 50055
targetPort: 50055
protocol: TCP
ingress:
enabled: false
- name: world-service
replicas: 1
image: world-service:latest
port: 50054
env:
SERVICE_NAME: "world-service"
tcp:
enabled: true
portName: world-service
port: 50054
targetPort: 50054
protocol: TCP
ingress:
enabled: false
tests:
enabled: true
services:
- name: api-service
testCommand: ["curl", "-f", "http://api-service:8080/health"]
image: curlimages/curl:latest

72
scripts/build_and_push.py Normal file
View File

@@ -0,0 +1,72 @@
import subprocess
import os
# Define your images, tags, and Dockerfile paths
images = ["api-service", "auth-service", "character-service", "database-service", "packet-service", "session-service", "world-service"]
dockerfile_paths = [
"../api-service/Dockerfile",
"../auth-service/Dockerfile",
"../character-service/Dockerfile",
"../database-service/Dockerfile",
"../packet-service/Dockerfile",
"../session-service/Dockerfile",
"../world-service/Dockerfile",
]
common_tag = "latest"
version_tag = "v0.1.0"
image_tag_prefix = "gitea.azgstudio.com/raven/"
build_context = "../"
def run_command(command):
"""Run a shell command and handle errors."""
try:
subprocess.run(command, check=True)
except subprocess.CalledProcessError as e:
print(f"Error: Command '{' '.join(command)}' failed with exit code {e.returncode}")
exit(1)
def build_images(images, dockerfile_paths, common_tag, version_tag, image_tag_prefix, build_context):
"""Build all Docker images."""
for image, dockerfile_path in zip(images, dockerfile_paths):
# Add the prefix to the image name
full_image_name = f"{image_tag_prefix}{image}"
# Build the image with both tags
print(f"Building {full_image_name}:{version_tag} and {full_image_name}:{common_tag} using Dockerfile at {dockerfile_path}...")
run_command([
"docker", "build",
"-t", f"{full_image_name}:{version_tag}",
"-t", f"{full_image_name}:{common_tag}",
"-f", dockerfile_path,
build_context
])
def push_images(images, common_tag, version_tag, image_tag_prefix):
"""Push all Docker images."""
for image in images:
# Add the prefix to the image name
full_image_name = f"{image_tag_prefix}{image}"
# Push both tags
print(f"Pushing {full_image_name}:{version_tag}...")
run_command(["docker", "push", f"{full_image_name}:{version_tag}"])
print(f"Pushing {full_image_name}:{common_tag}...")
run_command(["docker", "push", f"{full_image_name}:{common_tag}"])
if __name__ == "__main__":
script_dir = os.path.dirname(os.path.abspath(__file__))
os.chdir(script_dir)
# Build all images first
print("Starting the build phase...")
build_images(images, dockerfile_paths, common_tag, version_tag, image_tag_prefix, build_context)
# Push all images after builds are complete
print("Starting the push phase...")
push_images(images, common_tag, version_tag, image_tag_prefix)