1. Home
  2. Docs
  3. Infrastructure
  4. ERPNext

ERPNext

Installing ERPNext on MicroK8s

Phases:

  1. Add ERPNext Helm chart repository
  2. Prepare Kubernetes
  3. Install frappe/erpnext Helm chart
  4. Create Resources

1. Add ERPNext Helm chart repository

kubectl config use-context microk8s
helm repo add frappe https://helm.erpnext.com
helm repo update

2. Prepare Kubernetes

This phase includes:

  1. LoadBalancer Service
  2. Certificate Management
  3. MariaDB
  4. Shared Filesystem

2.1. LoadBalancer Service

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm install ingress-nginx ingress-nginx/ingress-nginx

2.3. MariaDB Installation (and AWS RDS MariaDB Workaround)

See ERPNext Helm chart > Prepare Kubernetes > MariaDB. Changes:

  • Container image tag: 10.4 (AWS RDS MariaDB already supports this per June 2020)
  • For local development, set slave.replicas to 0.
  • You may want to set master.persistence.size (default is 8Gi).
  • For DigitalOcean, set master.persistence.storageClass and slave.persistence.storageClass to "do-block-storage".

ERPNext AWS RDS MariaDB bug workaround: Due to #22658, our workaround is:

  1. Install a temporary MariaDB using Helm chart.
  2. Install ERPNext and create site using that MariaDB.
  3. Backup from Kubernetes MariaDB and restore into AWS RDS MariaDB. (see section “Moving (Temporary) MariaDB Database to AWS RDS MariaDB” below for details)
  4. Reconfigure ERPNext to use AWS RDS MariaDB.
  5. Delete the temporary Kubernetes MariaDB.

To install:

helm install -n mariadb mariadb bitnami/mariadb -f values-production.yaml

MariaDB Host should be mariadb.mariadb.svc.cluster.local. Check the StatefulSet progress:

$ kubectl get statefulset -n mariadb -o wide
NAME             READY   AGE   CONTAINERS        IMAGES
mariadb-master   0/1     12m   mariadb,metrics   docker.io/bitnami/mariadb:10.4,docker.io/bitnami/mysqld-exporter:0.12.1-debian-10-r146
mariadb-slave    0/1     12m   mariadb,metrics   docker.io/bitnami/mariadb:10.4,docker.io/bitnami/mysqld-exporter:0.12.1-debian-10-r146

You may get error due to PVC’s storage class:

ceefour@amanah:~/project/lovia/lovia-devops/erpnext$ kubectl describe statefulset -n mariadb mariadb-master
...
Events:
  Type     Reason        Age                  From                    Message
  ----     ------        ----                 ----                    -------
  Warning  FailedCreate  12m (x12 over 12m)   statefulset-controller  create Pod mariadb-master-0 in StatefulSet mariadb-master failed error: failed to create PVC data-mariadb-master-0: persistentvolumeclaims "data-mariadb-master-0" is forbidden: Internal error occurred: 2 default StorageClasses were found
  Warning  FailedCreate  119s (x18 over 12m)  statefulset-controller  create Claim data-mariadb-master-0 for Pod mariadb-master-0 in StatefulSet mariadb-master failed error: persistentvolumeclaims "data-mariadb-master-0" is forbidden: Internal error occurred: 2 default StorageClasses were found

To monitor deployment progress, use:

ceefour@amanah:~/project/lovia/lovia-devops/erpnext$ kubectl get pods -w --namespace mariadb -l release=mariadb
NAME               READY   STATUS    RESTARTS   AGE
mariadb-master-0   0/2     Pending   0          7s
mariadb-master-0   0/2     Pending   0          9s
mariadb-master-0   0/2     ContainerCreating   0          9s
mariadb-master-0   0/2     Running             0          35s

2.4. Shared Filesystem (NFS Server Provisioner)

Tutorial by DigitalOcean: https://www.digitalocean.com/community/tutorials/how-to-set-up-readwritemany-rwx-persistent-volumes-with-nfs-on-digitalocean-kubernetes

Save as nfs-server-provisioner-values.yaml: (you can change the size as you want, for example 20Gi for production)

persistence:
  enabled: true
  storageClass: "microk8s-hostpath"
  size: 8Gi

storageClass:
  defaultClass: true

To list storage classes in your Kubernetes cluster, use:

kubectl get storageclass

For production in DigitalOcean Kubernetes, you can use 22Gi (need to have 2 Gi spare space for overhead, since ERPNext will need pure 20 Gi). DigitalOcean’s block storage class is do-block-storage. WARNING: persistence.storageClass is needed! If you don’t fill it, nfs-server-provisioner-0 will store in EmptyDir instead, which is definitely not what you want. Example:

persistence:
  enabled: true
  storageClass: "do-block-storage"
  size: 22Gi

storageClass:
  defaultClass: true

Install:

helm install nfs-server-provisioner stable/nfs-server-provisioner -f nfs-server-provisioner-values.yaml

Storage class to be used by ERPNext is “nfs“. You can check this by using:

$ kubectl get storageclass
NAME                         PROVISIONER                            RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
do-block-storage (default)   dobs.csi.digitalocean.com              Delete          Immediate           true                   93d
nfs                          cluster.local/nfs-server-provisioner   Delete          Immediate           true                   6m23s

Check if nfs-server-provisioner-0 pod is Running:

kubectl describe po nfs-server-provisioner-0

The PVC data-nfs-server-provisioner-0 should exist that is used by nfs-server-provisioner as backing store.

kubectl describe pvc data-nfs-server-provisioner-0
kubectl get pvc -A

Note: If you want to delete this, not enough to just helm delete nfs-server-provisioner but also need to kubectl delete pvc data-nfs-server-provisioner-0

3. Install frappe/erpnext Helm chart

Create erpnext-values.yaml so you can helm upgrade later: (note: by default erpnext’s PVC persistence.size is 8Gi, change to at least 20Gi for production)

mariadbHost: mariadb.mariadb.svc.cluster.local
persistence:
  storageClass: nfs
  size: 8Gi

nginxImage:
  # repository: registry.gitlab.com/lovia/frappe_docker/lovia-nginx
  tag: version-13-beta
pythonImage:
  # repository: registry.gitlab.com/lovia/frappe_docker/lovia-worker
  tag: version-13-beta
# frappe/frappe-socketio
socketIOImage:
  tag: version-13-beta

# imagePullSecrets: 
#   - name: regcred

The Helm values above use ERPNext images without custom app.

Install ERPNext without custom app:

kubectl create namespace erpnext
helm install frappe-bench-0001 --namespace erpnext frappe/erpnext -f erpnext-values.yaml

Note that an erpnext pod contains 2 containers: erpnext-assets and erpnext-python. By default the pod itself has replicaCount of 1.

Ensure frappe-bench-0001-erpnext pod PVC is working/Bound:

ceefour@amanah:~/project/erpnext-local$ kubectl get pvc -A
NAMESPACE            NAME                            STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS        AGE
container-registry   registry-claim                  Bound    pvc-1f86ebc5-2239-4af1-8b84-28cd3e07e8d1   20Gi       RWX            microk8s-hostpath   59m
default              data-nfs-server-provisioner-0   Bound    pvc-9529a0ff-329c-47d9-93e9-0f3af4d6bad2   1Gi        RWO            microk8s-hostpath   67s
erpnext              frappe-bench-0001-erpnext       Bound    pvc-3b96af59-60f8-469a-88c4-2de73e506a89   8Gi        RWX            nfs                 15m
mariadb              data-mariadb-master-0           Bound    pvc-95e4caf2-96be-4669-a639-798ca3b68b5f   8Gi        RWO            microk8s-hostpath   35m

You’ll get the following services:

ceefour@amanah:~/project/erpnext-local$ kubectl get svc -n erpnext
NAME                                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)     AGE
frappe-bench-0001-erpnext                  ClusterIP   10.152.183.19    <none>        80/TCP      14s
frappe-bench-0001-erpnext-redis-cache      ClusterIP   10.152.183.220   <none>        13000/TCP   14s
frappe-bench-0001-erpnext-redis-queue      ClusterIP   10.152.183.64    <none>        12000/TCP   14s
frappe-bench-0001-erpnext-redis-socketio   ClusterIP   10.152.183.165   <none>        11000/TCP   14s
frappe-bench-0001-erpnext-socketio         ClusterIP   10.152.183.152   <none>        9000/TCP    14s

Set the mariadb-root-password secret with key password:

kubectl create secret -n erpnext generic mariadb-root-password --from-literal=password=super_secret_password

Troubleshooting: Warning FailedMount 2m13s kubelet, amanah MountVolume.SetUp failed for volume “pvc-3b96af59-60f8-469a-88c4-2de73e506a89” : mount failed: exit status 32

Problem: This happens on erpnext describe pod (kubectl describe po -n erpnext frappe-bench-0001-erpnext-erpnext-7bd5c94d46-lnv8m).

Solution: Hendy: For some reason, after I deleted the pod, then it works.

Post-install (No site yet)

You can open browser on service/frappe-bench-0001-erpnext‘s Cluster IP on the same computer, e.g. http://10.152.183.171/ . You should get a “Sorry! We will be back soon.” message. Now you can create a Site and Ingress.

4. Create Resources

Reference: ERPNext Helm chart > Kubernetes Resources.

  1. Create New Site Job.
  2. Create New Site Ingress.
  3. Create CronJob to take backups and push them to cloud regularly.

4.1. Create New Site Job

Create add-example-site-job.yaml. Important things to change:

  • Make sure you have set Kubernetes secret mariadb-root-password, key secret, in namespace erpnext
  • Change the frappe/erpnext-worker version to the latest specific stable version, or alternatively use a rolling tag like v12.
  • Change SITE_NAME to your real subdomain name
  • Generate & save admin password using Bitwarden, and set it as ADMIN_PASSWORD

AWS RDS MariaDB Notes: The following attempts did not work. Instead, see workaround in “Moving (Temporary) MariaDB Database to AWS RDS MariaDB” section below.

kubectl exec -n erpnext frappe-bench-0001-erpnext-worker-d-847966697-fwkwc -it -- bash
# IGNORE the commands below, they were experimental and turns out not needed, just skip to "common_site_config.json" part
#apt update
#apt install nano less
#export SITE_NAME=erp.lovia.life
#export DB_ROOT_USER=root
#export INSTALL_APPS=erpnext
#export MYSQL_ROOT_PASSWORD=
#export ADMIN_PASSWORD=
# need to patch GRANT ALL PRIVILEGES: nano /home/frappe/frappe-bench/commands/new.py
# GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES, CREATE VIEW, EVENT, TRIGGER, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EXECUTE
#. /home/frappe/frappe-bench/env/bin/activate
#su frappe -c 'python ~/frappe-bench/commands/new.py'

Then use “cat” (since nano, vim, vi, none of them are available) to update common_site_config.json as follows:

{
    "rds_db": 1,
    "db_host": "****************",
    "db_port": 3306,
    "redis_cache": "redis://frappe-bench-0001-erpnext-redis-cache:13000",
    "redis_queue": "redis://frappe-bench-0001-erpnext-redis-queue:12000",
    "redis_socketio": "redis://frappe-bench-0001-erpnext-redis-socketio:11000",
    "socketio_port": 9000
}

Create job to create site. Important: Make sure the worker version here matches the image tags used by Frappe Bench Helm chart. Otherwise, you’ll get error i.e. “Sorry! We will be back soon.” (not!)

apiVersion: batch/v1
kind: Job
metadata:
  name: create-erp-example-com
spec:
  backoffLimit: 0
  template:
    spec:
      securityContext:
        supplementalGroups: [1000]
      containers:
      - name: create-site
        image: frappe/erpnext-worker:v13-beta
        args: ["new"]
        imagePullPolicy: IfNotPresent
        volumeMounts:
          - name: sites-dir
            mountPath: /home/frappe/frappe-bench/sites
        env:
          - name: "SITE_NAME"
            value: erpnext-example.svc.cluster.local
          - name: "DB_ROOT_USER"
            value: root
          - name: "MYSQL_ROOT_PASSWORD"
            valueFrom:
              secretKeyRef:
                name: mariadb-root-password
                key: password
          - name: "ADMIN_PASSWORD"
            value: super_secret_password
          - name: "INSTALL_APPS"
            value: "erpnext"
      restartPolicy: Never
      volumes:
        - name: sites-dir
          persistentVolumeClaim:
            claimName: frappe-bench-0001-erpnext
            readOnly: false

Note: If you use custom image (including custom app), you can change “INSTALL_APPS” value to e.g. “erpnext,lovia“.

kubectl create -n erpnext -f add-example-site-job.yaml
kubectl -n erpnext describe job create-erp-example-com

You’ll get a new Job pod for that site, e.g. create-erp-example-com-c2wzv. You can follow logs on that site’s job: (this will take about 2 minutes, after that the pod’s status will go to Completed)

ceefour@amanah:~/project/erpnext-local$ kubectl logs -f -n erpnext create-erp-example-com-c2wzv
Attempt 1 to connect to mariadb.mariadb.svc.cluster.local:3306
Attempt 1 to connect to frappe-bench-0001-erpnext-redis-queue:12000
Attempt 1 to connect to frappe-bench-0001-erpnext-redis-cache:13000
Attempt 1 to connect to frappe-bench-0001-erpnext-redis-socketio:11000
Connections OK
Created user _684bfe87ae59e1a8
Created database _684bfe87ae59e1a8
Granted privileges to user _684bfe87ae59e1a8 and database _684bfe87ae59e1a8
Starting database import...
Imported from database /home/frappe/frappe-bench/apps/frappe/frappe/database/mariadb/framework_mariadb.sql

Installing frappe...
Updating DocTypes for frappe        : [========================================]
Updating country info               : [========================================]

Installing erpnext...
Updating DocTypes for erpnext       : [========================================]
Updating customizations for Address
*** Scheduler is disabled ***

Troubleshooting AWS RDS MariaDB: Unfortunately, GRANT ALL won’t work on AWS RDS MariaDB. The rather good news is frappe/database/db_manager.py has supported AWS RDS since v12.8. You need to apply the AWS RDS MariaDB workaround.

Troubleshooting AWS RDS MariaDB Part 2:

Updating country info               : [========================================]

Installing erpnext...
Updating DocTypes for erpnext       : [========================================]
Updating customizations for Address
*** Scheduler is disabled ***
ERROR 1054 (42S22) at line 1: Unknown column 'ERROR (RDS): SUPER PRIVILEGE CANNOT BE GRANTED OR MAINTAINED' in 'field list'
ERROR 1396 (HY000) at line 1: Operation ALTER USER failed for '_9a6f28ddcbb1acb1'@'%'
ERROR 1044 (42000) at line 1: Access denied for user 'root'@'%' to database '_9a6f28ddcbb1acb1'

Troubleshooting pymysql.err.InternalError: Packet sequence number wrong with frappe/erpnext-worker:v13.0.0-beta.3 and also v12 with rds_db=1: Caused by AWS RDS MariaDB blocking the IP address:

ERROR 1129 (HY000): Host ‘…’ is blocked because of many connection errors; unblock with ‘mysqladmin flush-hosts’

Quick fix is to run: mysqladmin -h... -u... -p flush-hosts

A longer-term solution is to find out what actually caused the errors, inspect MariaDB variables max_connections and max_connect_errors, and increase the maximum limits below.

show variables like "max_connections";
show variables like "max_connect_errors";

For example, you can set (using AWS RDS MariaDB Parameter Group) max_connect_errors to 10000 and max_connections to 200.

Some other people say this is caused by multi-threading.

Attempt 1 to connect to frappe-bench-0001-erpnext-redis-queue:12000
Attempt 1 to connect to frappe-bench-0001-erpnext-redis-cache:13000
Attempt 1 to connect to frappe-bench-0001-erpnext-redis-socketio:11000
Connections OK
Traceback (most recent call last):
  File "/home/frappe/frappe-bench/commands/new.py", line 127, in <module>
    main()
  File "/home/frappe/frappe-bench/commands/new.py", line 75, in main
    db_port=db_port,
  File "/home/frappe/frappe-bench/apps/frappe/frappe/commands/site.py", line 88, in _new_site
    db_password=db_password, db_type=db_type, db_host=db_host, db_port=db_port, no_mariadb_socket=no_mariadb_socket)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/installer.py", line 35, in install_db
    setup_database(force, source_sql, verbose, no_mariadb_socket)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/__init__.py", line 16, in setup_database
    return frappe.database.mariadb.setup_db.setup_database(force, source_sql, verbose, no_mariadb_socket=no_mariadb_socket)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/mariadb/setup_db.py", line 39, in setup_database
    if force or (db_name not in dbman.get_database_list()):
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/db_manager.py", line 61, in get_database_list
    return [d[0] for d in self.db.sql("SHOW DATABASES")]
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/database.py", line 122, in sql
    self.connect()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/database.py", line 75, in connect
    self._conn = self.get_connection()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/mariadb/database.py", line 91, in get_connection
    local_infile = frappe.conf.local_infile)
  File "/home/frappe/frappe-bench/env/lib/python3.7/site-packages/pymysql/__init__.py", line 94, in Connect
    return Connection(*args, **kwargs)
  File "/home/frappe/frappe-bench/env/lib/python3.7/site-packages/pymysql/connections.py", line 325, in __init__
    self.connect()
  File "/home/frappe/frappe-bench/env/lib/python3.7/site-packages/pymysql/connections.py", line 598, in connect
    self._get_server_information()
  File "/home/frappe/frappe-bench/env/lib/python3.7/site-packages/pymysql/connections.py", line 975, in _get_server_information
    packet = self._read_packet()
  File "/home/frappe/frappe-bench/env/lib/python3.7/site-packages/pymysql/connections.py", line 671, in _read_packet
    % (packet_number, self._next_seq_id))
pymysql.err.InternalError: Packet sequence number wrong - got 1 expected 0

ERPNext v12 vs v13-beta? See thread for discussion on v12 vs v13 stability. See: https://discuss.erpnext.com/t/release-note-erpnext-and-frappe-version-13-beta-3/63308/14

Option 1: Access Website using /etc/hosts (Temporarily/Development)

Now edit your /etc/hosts file:

10.152.183.171 erpnext-example.svc.cluster.local

And open the browser at the SITE_NAME, e.g. http://erpnext-example.svc.cluster.local/ . You should get a good welcome. 🙂 Congratulations!

Option 2: Access Website using DNS, Ingress, and SSL (Production)

1. Create CNAME DNS record erp.lovia.life pointing to load balancer or nginx node’s external IP address (not proxied).

2. Create frappe-bench-0001-erpnext-ingress.yaml:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: frappe-bench-0001-erpnext-ingress
  namespace: erpnext
  annotations:
    kubernetes.io/ingress.class: nginx
    # https://github.com/nginxinc/kubernetes-ingress/issues/21#issuecomment-521338887
    nginx.ingress.kubernetes.io/proxy-body-size: 64m
    # https://discuss.erpnext.com/t/erpnext-ssl-https-config-not-working-with-nginx/11314 (default is 60)
    nginx.ingress.kubernetes.io/proxy-read-timeout: '120'
    # https://pumpingco.de/blog/using-signalr-in-kubernetes-behind-nginx-ingress/
    nginx.ingress.kubernetes.io/affinity: cookie
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  # REQUIRES helm cert-manager
  tls:
    - hosts:
        - erp.lovia.life
      secretName: frappe-bench-0001-erpnext-tls
  rules:
    - host: erp.lovia.life
      http:
        paths:
          - backend:
              serviceName: frappe-bench-0001-erpnext
              servicePort: 80

2. Deploy the ingress:

kubectl apply -f frappe-bench-0001-erpnext-ingress.yaml

To check certificate issuance progress:

ceefour@amanah:~/project/lovia/lovia-devops/erpnext$ kubectl describe cert -n erpnext frappe-bench-0001-erpnext-tls
...
Events:
  Type    Reason        Age   From          Message
  ----    ------        ----  ----          -------
  Normal  GeneratedKey  3m3s  cert-manager  Generated a new private key
  Normal  Requested     3m3s  cert-manager  Created new CertificateRequest resource "frappe-bench-0001-erpnext-tls-4179684101"
  Normal  Issued        105s  cert-manager  Certificate issued successfully

3. Access ERPNext at https://erp.lovia.life/desk

Login using “administrator”

Login using user “administrator” and the ADMIN_PASSWORD that you’ve set before.

After logging in as administrator, you’ll need to set up your first company. After filling the forms, it’ll take some time to set up (about 2 minutes). You can follow kubectl logs for the erpnext pod to check progress, or to diagnose in case there’s an error.

Site Management Operations

Migrate Sites (e.g. to newer ERPNext Version)

See https://helm.erpnext.com/kubernetes-resources/create-migrate-sites-job

Migrate database: Create Kubernetes Job to run commands/migrate.py, e.g. migrate-sites-2020-08-09.yaml: (note: the following assumes you’re already using custom ERPNext Docker image lovia-worker)

apiVersion: batch/v1
kind: Job
metadata:
  name: migrate-sites-2020-08-09
spec:
  backoffLimit: 1
  template:
    spec:
      securityContext:
        supplementalGroups: [1000]
      containers:
      - name: migrate-sites
        # image: frappe/erpnext-worker:version-13-beta
        image: registry.gitlab.com/lovia/frappe_docker/lovia-worker:version-13-beta
        imagePullPolicy: Always
        args: ["migrate"]
        volumeMounts:
          - name: sites-dir
            mountPath: /home/frappe/frappe-bench/sites
      imagePullSecrets: 
        - name: regcred
      restartPolicy: Never
      volumes:
        - name: sites-dir
          persistentVolumeClaim:
            claimName: frappe-bench-0001-erpnext
            readOnly: false

Then run it:

kubectl create -n erpnext -f migrate-sites-2020-08-09.yaml

Then you’ll need to ensure Kubernetes is running the desired nginx, python, and socketio image versions. Either you change erpnext-values.yaml, or manually deleting the pods and let Kubernetes recreate the pods with newest images (when using pullPolicy=Always).

Push Backup to AWS S3

Push backup to AWS S3: See https://github.com/frappe/frappe_docker/blob/develop/docs/site-operations.md

Moving (Temporary) MariaDB Database to AWS RDS MariaDB

After installing ERPNext using a “temporary” MariaDB database, it’s better to move it to AWS RDS MariaDB so that the database is easier to maintain.

You’ll need to edit sites/common_site_config.json and sites/YOUR_SITE_site_config.json.

If you have access to bench, you can also use bench set-mariadb-host.

Resources:

Here’s how to move from temporary MariaDB database to AWS RDS MariaDB:

  1. Open bash inside frappe-bench-0001-erpnext-worker by using kubectl exec.
    Alternatively you can run client using MariaDB Kubernetes. (check using: helm get notes-n mariadb mariadb)
    kubectl run mariadb-client --rm --tty -i --restart='Never' --image docker.io/bitnami/mariadb:10.4 --namespace mariadb --command -- bash
  2. Inside the mariadb-client shell, dump the temporary database: (–routines is important! MySQL for some strange reason disabled this by default! But it seems ERPNext doesn’t use them… yet?)
    mysqldump --routines --opt -h mariadb.mariadb.svc.cluster.local -u root -p (db_name) &gt; FILENAME.sql
  3. Create the new user on AWS RDS MariaDB
CREATE USER (user_name)@'%' IDENTIFIED BY (password_in_quotes);
CREATE DATABASE (db_name) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON (db_name).* TO (user_name)@'%';
FLUSH PRIVILEGES;
  1. Restore the database to AWS RDS MariaDB:
    mysql -h (RDS_host) -u (user_name) -p (db_name) &lt; FILENAME.sql
  2. Open bash inside frappe-bench-0001-erpnext-worker by using: kubectl exec -n erpnext frappe-bench-0001-erpnext-worker-d-89bf7874c-4mztc -it -- bash
  3. You may want to install nano: apt update &amp;&amp; apt -y install nano
  4. Edit SITE/site_config.json and change the db_host, also add "rds_db": 1
  5. Edit common_site_config.json and change the db_host, also add "rds_db": 1
  6. Restart all pods inside erpnext namespace: kubectl delete --all pods --namespace=erpnext
    After it’s “quite done”, press Ctrl+C (otherwise it will get stuck).
  7. You can delete the temporary mariadb: helm delete -n mariadb mariadb
  8. Delete MariaDB’s PVC: kubectl delete pvc -n mariadb data-mariadb-master-0

“Uninstall/Reinstall” ERPNext from Kubernetes

Basically you do the reverse of installation:

  1. (If you just want to reinstall, you don’t need to delete ingress). Delete ERPNext’s ingress: kubectl delete -f frappe-bench-0001-erpnext-ingress.yaml
  2. Delete the ERPNext Helm release: helm delete -n erpnext frappe-bench-0001
  3. Delete the MariaDB database Helm chart: helm delete -n mariadb mariadb
  4. Ensure no ERPNext pods are stuck: kubectl get po -n erpnext
  5. Delete MariaDB’s PVC: kubectl delete pvc -n mariadb data-mariadb-master-0
  6. Delete the nfs-server-provisioner NFS: helm delete -n nfs-server-provisioner nfs-server-provisioner
  7. Delete NFS PVC: kubectl delete pvc data-nfs-server-provisioner-0

Troubleshooting: Email Not Sent (Yandex.Mail)

First, check Inbound email (IMAP), because it is easiest to get working. If it’s working, we can check the Outgoing email configuration.

Check Email Queue > List.

References: https://discuss.erpnext.com/t/emails-not-sendng/26862/7

About Frappe Cloud

There is Frappe Cloud that can be used to host ERPNext instances starting at $10/mo per site (1 daily hour), $25/mo per site (2 daily hours) to $50/mo per site (4 daily hours). It is an interesting offer instead of running our own ERPNext inside Kubernetes, with MariaDB, etc. To compare, in DigitalOcean Kubernetes:

  • $10 = 1 Gi memory limit (from raw 2 GB)
  • $20 = 3 Gi memory limit (from raw 4 GB)
  • $40 = 6 Gi memory limit (from raw 8 GB)

REST API

Resources:

API Key & API Secret

  1. Go to your user’s User Settings
  2. API Access > Generate API Key, save the API Secret. Then refresh the browser to see the API Key. You will need both API Key and API Secret to use REST API.

To call authenticated REST API, use Basic authentication in header with username=API Key and password=API Secret.

Reference:

3-day Temporary Token (sid)

First you’ll need to use /api/method/login and get the sid which can be used as token: HTTP request header.

List of Document Types under Settings -> DocType.

GET a list of documents with fields
POST to create a new document
Example POST result

Developing Custom App in ERPNext

See ERPNext > Developing Custom Apps.

Store File Uploads/Attachments to Amazon S3

This is not built-in supported. However there is custom app zerodhatech/frappe-attachments-s3 which is still maintained as of July 2020.

The caveat is that files will still be stored on NFS (or Ceph) first, then mirrored to S3. So it is not a native feature (unlike Strapi’s Provider).

Troubleshooting: HR Manager Cannot See All Employees

Make sure in HR Manager’s user, “Create User Permission” is unchecked. If it’s already checked, unlink the user from that employee, then re-link.

Selection_080

Reference: https://discuss.erpnext.com/t/as-an-hr-manager-i-cannot-see-all-employees/44548/8

Email Sending & Incoming Configuration

AWS SES

First, make sure that the domain is verified in AWS SES in region ap-southeast-1.

Email Domain

Set email domain as follows. “Use TLS” actually means “Use STARTTLS”.

Email Account: Default Sending

Rename the account to “Lovia”. Options “Always use Account’s Email” and “Always use Account’s Name” needs to be checked, so it will not “pretend” to be someone else. Each user should have their own Email Account document if want to send under own name.

Articles

Was this article helpful to you? Yes No

How can we help?

Leave a Reply

Your email address will not be published. Required fields are marked *