Skip to content

Instantly share code, notes, and snippets.

@revant
Last active August 6, 2024 17:26
Show Gist options
  • Save revant/1328e3367c3042fd91c447859fb23dd1 to your computer and use it in GitHub Desktop.
Save revant/1328e3367c3042fd91c447859fb23dd1 to your computer and use it in GitHub Desktop.
AWS EKS Fargate ERPNext

Prerequisites

  • EKS Fargate profiles for <fargate-profile-namespace>. Guide
  • EKS Fargate coredns profile for coredns pods to run (create profile for kube-system namespace, refer guide from previous step)
  • EFS CSI Driver installed, mount points set and pv.yaml created. Refer Guide
  • EKS ALB Controller, refer Guide.

Install Helm

Refer Helm Installation to install helm command

Add Frappe/ERPNext Helm Chart Repo

helm repo add frappe https://helm.erpnext.com
helm repo update

Update values.yaml with configuration variables

code erpnext-values.yaml

Change the following values:

  • mariadbHost: set to hostname of managed db, e.g. core-cluster.cluster-abc.region.rds.amazonaws.com
  • redisQueueHost: set to uri of elasticache with database, e.g. abc.pqr.0001.xyz.cache.amazonaws.com:6379/0
  • redisCacheHost: set to uri of elasticache with database, e.g. abc.pqr.0001.xyz.cache.amazonaws.com:6379/1
  • redisSocketIOHost: set to uri of elasticache with database, e.g. abc.pqr.0001.xyz.cache.amazonaws.com:6379/2

Install helm chart

helm install <release-name> -n <fargate-profile-namespace> frappe/erpnext -f erpnext-values.yaml

Update create-site.yaml

code create-site.yaml

Change the following values:

  • <site.name.com> change to domain name of the site to be created. e.g. admin.fxr.one
  • <db-root-user> change to mysql root user. e.g. frappe
  • <db-name> change to db-name of database to be created for site.
  • <SITES_PVC_NAME> change to PVC created after helm chart install, get it using command kubectl get pvc -n <fargate-profile-namespace>.
  • <base64-encoded-site-db-password> replace with base64 encoded db-password for db to be created for site.
  • <base64-encoded-mariadb-root-password> replace with base64 encoded mariadb root password. e.g. echo -n "secretpassword" | base64, use -n to escape newline in base64.
  • <base64-encoded-site-admin-password> replace with base64 encoded site admin password. e.g. echo -n "secretpassword" | base64, use -n to escape newline in base64.

Create new site job

kubectl apply -f create-site.yaml -n <fargate-profile-namespace>

Update Ingress yaml

code erpnext-ingress.yaml

Change the following values:

  • <site.name.com> change to domain name of the site to be created. e.g. admin.fxr.one
  • <certificate-arn> change to certificate arn, e.g. arn:aws:acm:ap-southeast-1:111122223333:certificate/4773ec2d-d90e-499d-9e9a-52c6956a55cb
  • <erpnext-service-name> change to service created after helm chart install, get it using command kubectl get svc -n <fargate-profile-namespace>. DO NOT USE socketio service name.

Create ingress

kubectl apply -n <fargate-profile-namespace> -f erpnext-ingress.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: create-new-site-<site.name.com>
spec:
backoffLimit: 1
template:
spec:
containers:
- name: create-site
image: frappe/erpnext-worker:v13.0.0-beta.4
command: ["/bin/bash", "-c"]
args:
- >
sed -i -e "s/\`name\` varchar(100) DEFAULT NULL,/\`name\` varchar(100),/g" /home/frappe/frappe-bench/apps/frappe/frappe/database/mariadb/framework_mariadb.sql;
sed -i -e "s/ROW_FORMAT=COMPRESSED/ROW_FORMAT=DYNAMIC/g" /home/frappe/frappe-bench/apps/frappe/frappe/database/mariadb/framework_mariadb.sql;
sed -i -e "s/ROW_FORMAT=COMPRESSED/ROW_FORMAT=DYNAMIC/g" /home/frappe/frappe-bench/apps/frappe/frappe/database/mariadb/database.py;
sed -i -e "s/ROW_FORMAT=COMPRESSED/ROW_FORMAT=DYNAMIC/g" /home/frappe/frappe-bench/apps/frappe/frappe/database/mariadb/schema.py;
bench new-site $SITE_NAME --no-mariadb-socket --db-name $DB_NAME --db-password $DB_PASSWORD --mariadb-root-username $DB_ROOT_USER --mariadb-root-password $MYSQL_ROOT_PASSWORD --admin-password $ADMIN_PASSWORD --install-app erpnext;
chown -R frappe:frappe /home/frappe/frappe-bench/sites;
imagePullPolicy: IfNotPresent
volumeMounts:
- name: sites-dir
mountPath: /home/frappe/frappe-bench/sites
env:
- name: "SITE_NAME"
value: <site.name.com>
- name: "DB_NAME"
value: <db-name>
- name: "DB_PASSWORD"
valueFrom:
secretKeyRef:
key: siteDbPassword
name: <site.name.com>-passwords
- name: "DB_ROOT_USER"
value: <db-root-user>
- name: "MYSQL_ROOT_PASSWORD"
valueFrom:
secretKeyRef:
key: password
name: mariadb-root-password
- name: "ADMIN_PASSWORD"
valueFrom:
secretKeyRef:
key: adminPassword
name: <site.name.com>-passwords
- name: "INSTALL_APPS"
value: "erpnext"
restartPolicy: Never
volumes:
- name: sites-dir
persistentVolumeClaim:
claimName: <SITES_PVC_NAME>
readOnly: false
---
apiVersion: v1
data:
password: <base64-encoded-mariadb-root-password>
kind: Secret
metadata:
name: mariadb-root-password
type: Opaque
---
apiVersion: v1
data:
adminPassword: <base64-encoded-site-admin-password>
siteDbPassword: <base64-encoded-site-db-password>
kind: Secret
metadata:
name: <site.name.com>-passwords
type: Opaque

Note: Use this in pipelines along with aws cli.

login_cmd=$(aws ecr get-login --no-include-email --region ap-southeast-1 | sed 's;https://;;g')
username=$(echo $login_cmd | cut -d " " -f 4)
password=$(echo $login_cmd | cut -d " " -f 6)
endpoint=$(echo $login_cmd | cut -d " " -f 7)

# Delete old secret
kubectl -n <fargate-profile-namespace> delete secret aws-ecr-registry

# Create fresh secret
kubectl -n <fargate-profile-namespace> create secret docker-registry aws-ecr-registry \
  --docker-server=$endpoint --docker-username=$username --docker-password=$password
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: <site.name.com>
labels:
app.kubernetes.io/instance: <erpnext-service-name>
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/certificate-arn: <certificate-arn>
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
alb.ingress.kubernetes.io/scheme: internet-facing
spec:
rules:
- host: <site.name.com>
http:
paths:
- backend:
serviceName: <erpnext-service-name>
servicePort: 80
path: /
# Default values for erpnext.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
nginxImage:
repository: frappe/erpnext-nginx
tag: v13.0.0-beta.4
pullPolicy: IfNotPresent
pythonImage:
repository: frappe/erpnext-worker
tag: v13.0.0-beta.4
pullPolicy: IfNotPresent
socketIOImage:
repository: frappe/frappe-socketio
tag: v13.0.0-beta.4
pullPolicy: IfNotPresent
# Asset Image Env Variables
frappePyPort: "8000"
socketIOPort: "9000"
# Python Image Env Variables
mariadbHost: "core-cluster.cluster-abc.region.rds.amazonaws.com"
redisQueueHost: "redis://abc.pqr.0001.xyz.cache.amazonaws.com:6379/0"
redisCacheHost: "redis://abc.pqr.0001.xyz.cache.amazonaws.com:6379/0"
redisSocketIOHost: "redis://abc.pqr.0001.xyz.cache.amazonaws.com:6379/0"
# PostgreSQL related variables
postgresHost: ""
postgresPort: ""
migrateJob:
# Set this to true to run migrate as part of helm install/upgrade
enable: false
backup: true
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
# Specifies whether a service account should be created
create: true
podSecurityContext:
supplementalGroups: [1000]
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
service:
type: ClusterIP
port: 80
# Additional Services
socketIOService:
type: ClusterIP
port: 9000
redisSocketIOService:
type: ClusterIP
port: 11000
redisQueueService:
type: ClusterIP
port: 12000
redisCacheService:
type: ClusterIP
port: 13000
persistence:
enabled: true
# existingClaim: ""
size: 8Gi
storageClass: "efs-sc"
resources: {}
# If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
nodeSelector: {}
tolerations: []
affinity: {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment