Adding script for k8s deployment (#1359)

Also support feature for generating SSL certificate for domain when deploying on Kubernetes

Co-authored-by: GEEK Up Team <prj_legodevops@geekup.vn>
This commit is contained in:
Arpit Mohan 2020-10-30 09:51:05 +05:30 committed by GitHub
parent 75c84cbba7
commit 39ab488193
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1195 additions and 0 deletions

126
deploy/k8s/README.md Normal file
View File

@ -0,0 +1,126 @@
---
description: Appsmith stands for speed and getting started with Appsmith is just as fast.
---
# Getting started
You can begin using appsmith via our cloud instance or by deploying appsmith yourself
* [Using Appsmith Cloud](quick-start.md#appsmith-cloud) **\(recommended\):** Create a new application with just one click
* [Using Docker](quick-start.md#docker): Deploy anywhere using docker
## Appsmith Cloud
The fastest way to get started with appsmith is using our cloud-hosted version. It's as easy as
1. [Create an Account](https://app.appsmith.com/user/signup)
2. [Start Building](core-concepts/building-the-ui/)
## Prerequisites
* Ensure `kubectl` is installed and configured to connect to your cluster
* Install kubeclt: [kubernetes.io/vi/docs/tasks/tools/install-kubectl/](https://kubernetes.io/vi/docs/tasks/tools/install-kubectl/)
* Minikube: [Setup Kubectl](https://minikube.sigs.k8s.io/docs/handbook/kubectl/)
* Google Cloud Kubernetes: [Configuring cluster access for kubectl
](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl)
* Aws EKS: [Create a kubeconfig for Amazon EKS](https://docs.aws.amazon.com/eks/latest/userguide/create-kubeconfig.html)
* Microk8s: [Working with kubectl](https://microk8s.io/docs/working-with-kubectl)
* Kubernetes NGINX Ingress Controller must be enable on your cluster by default. Please make sure that you install the right version for your cluster
* Minikube: [Set up Ingress on Minikube with the NGINX Ingress Controller](https://kubernetes.io/docs/tasks/access-application-cluster/ingress-minikube/)
* Google Cloud Kubernetes: [Ingress with NGINX controller on Google Kubernetes Engine](https://kubernetes.github.io/ingress-nginx/deploy/)
* AWS EKS: [Install NGINX Controller for AWS EKS](https://kubernetes.github.io/ingress-nginx/deploy/#network-load-balancer-nlb)
* Microk8s: [Add on: Ingress](https://microk8s.io/docs/addon-ingress)
* Script tested on Minikube with Kubernetes v1.18.0
## Kubernetes
Appsmith also comes with an installation script that will help you configure Appsmith & deploy your app on Kubernetes cluster.
1. Fetch the **install.k8s.sh** script on the system you want to deploy appsmith
```bash
# Downloads install.sh
curl -O https://raw.githubusercontent.com/appsmithorg/appsmith/master/deploy/k8s/install.k8s.sh
```
2. Make the script executable
```bash
chmod +x install.k8s.sh
```
3. Run the script.
```bash
./install.k8s.sh
```
4. Check if all the pods are running correctly.
```bash
kubectl get pods
#Output should look like this
NAME READY STATUS RESTARTS AGE
appsmith-editor-cbf5956c4-2zxlz 1/1 Running 0 4m26s
appsmith-internal-server-d5d555dbc-qddmb. 1/1 Running 2 4m22s
imago-1602817200-g28b2 1/1 Running 0 4m39s
mongo-statefulset-0 1/1 Running 0 4m13s
redis-statefulset-0 1/1 Running 0 4m00s
```
5. Custom Appsmith's Configuration
* After you successfully run the script, all the configuration files have been downloaded and & stored into `<Installation Path>`
* If you want to update your app settings (ex: database host). Go to the `<Installation Path>/config-template`, update the corresponding value in the configmap file, then restart the pods.
* Below steps will help you update database hostname of your application:
* Open file `appsmith-configmap.yaml` in `<Installation Path>/config-template` folder
* Update the value of variable `APPSMITH_MONGODB_URI` to your database host name
* Run commands:
```
kubectl apply -f appsmith-configmap.yaml
kubectl scale deployment appsmith-internal-server --replicas=0
kubectl scale deployment appsmith-internal-server --replicas=1
```
{% hint style="success" %}
* You can access the running application on the **Ingress Endpoint** if you not chose to provide custom domain for your application .
```
kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
appsmith-ingress <none> * XXX.XXX.XX.XXX 80 2m
```
* You may need to wait 2-3 minutes before accessing the application to allow application start (depends on your cluster).
{% endhint %}
### Custom Domains
To host Appsmith on a custom domain, you can contact your domain registrar and update your DNS records. Most domain registrars have documentation on how you can do this yourself.
* [GoDaddy](https://in.godaddy.com/help/create-a-subdomain-4080)
* [Amazon Route 53](https://aws.amazon.com/premiumsupport/knowledge-center/create-subdomain-route-53/)
* [Digital Ocean](https://www.digitalocean.com/docs/networking/dns/how-to/add-subdomain/)
* [NameCheap](https://www.namecheap.com/support/knowledgebase/article.aspx/9776/2237/how-to-create-a-subdomain-for-my-domain)
* [Domain.com](https://www.domain.com/help/article/domain-management-how-to-update-subdomains)
{% hint style="warning" %}
* During the setup of Ingress Controller on your cloud. You will need to map your custom domain with the External IP of the controller before running the installation script
* Below is an example how to achieve the External IP of NGINX Ingress Controller
```
➜ kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer XX.XXX.X.XX XX.XX.XX.XXX 80:XXXXX/TCP,443:XXXXX/TCP 17h
ingress-nginx-controller-admission ClusterIP XX.XXX.X.XX <none> 443/TCP 17h
```
{% endhint %}
## Troubleshooting
If at any time you encounter an error during the installation process, reach out to **support@appsmith.com** or join our [Discord Server](https://discord.com/invite/rBTTVJp)
If you know the error and would like to reinstall Appsmith, simply delete the installation folder and the templates folder and execute the script again

563
deploy/k8s/install.k8s.sh Executable file
View File

@ -0,0 +1,563 @@
#!/bin/bash
set -o errexit
is_command_present() {
type "$1" >/dev/null 2>&1
}
is_mac() {
[[ $OSTYPE == darwin* ]]
}
# This function checks if the relevant ports required by Appsmith are available or not
# The script should error out in case they aren't available
check_k8s_setup() {
echo "Checking your k8s setup status"
if ! is_command_present kubectl; then
echo "Please install kubectl on your machine"
exit 1
else
if ! is_command_present jq; then
install_jq
fi
clusters=`kubectl config view -o json | jq -r '."current-context"'`
if [[ ! -n $clusters ]]; then
echo "Please setup a k8s cluster & config kubectl to connect to it"
exit 1
fi
k8s_minor_version=`kubectl version --short -o json | jq ."serverVersion.minor" | sed 's/[^0-9]*//g'`
if [[ $k8s_minor_version < 18 ]]; then
echo "+++++++++++ ERROR ++++++++++++++++++++++"
echo "Appsmith deployments require Kubernetes >= v1.18. Found version: v1.$k8s_minor_version"
echo "+++++++++++ ++++++++++++++++++++++++++++"
exit 1
fi;
fi
}
install_jq(){
if [ $package_manager == "brew" ]; then
brew install jq
elif [ $package_manager == "yum" ]; then
yum_cmd="sudo yum --assumeyes --quiet"
$yum_cmd install jq
else
apt_cmd="sudo apt-get --yes --quiet"
$apt_cmd update
$apt_cmd install jq
fi
}
check_os() {
if is_mac; then
package_manager="brew"
desired_os=1
os="Mac"
return
fi
os_name="$(cat /etc/*-release | awk -F= '$1 == "NAME" { gsub(/"/, ""); print $2; exit }')"
case "$os_name" in
Ubuntu*)
desired_os=1
os="ubuntu"
package_manager="apt-get"
;;
Debian*)
desired_os=1
os="debian"
package_manager="apt-get"
;;
Red\ Hat*)
desired_os=1
os="red hat"
package_manager="yum"
;;
CentOS*)
desired_os=1
os="centos"
package_manager="yum"
;;
*)
desired_os=0
os="Not Found"
esac
}
overwrite_file() {
local relative_path="$1"
local template_file="$2"
local full_path="$install_dir/$relative_path"
echo "Copy $template_file to $full_path"
if [[ -f $full_path ]] && ! confirm y "File $relative_path already exists. Would you like to replace it?"; then
rm -f "$template_file"
else
mv -f "$template_file" "$full_path"
fi
}
# This function prompts the user for an input for a non-empty Mongo root password.
read_mongo_password() {
read -srp 'Set the mongo password: ' mongo_root_password
while [[ -z $mongo_root_password ]]; do
echo ""
echo ""
echo "+++++++++++ ERROR ++++++++++++++++++++++"
echo "The mongo password cannot be empty. Please input a valid password string."
echo "++++++++++++++++++++++++++++++++++++++++"
echo ""
read -srp 'Set the mongo password: ' mongo_root_password
done
}
# This function prompts the user for an input for a non-empty Mongo username.
read_mongo_username() {
read -rp 'Set the mongo root user: ' mongo_root_user
while [[ -z $mongo_root_user ]]; do
echo ""
echo "+++++++++++ ERROR ++++++++++++++++++++++"
echo "The mongo username cannot be empty. Please input a valid username string."
echo "++++++++++++++++++++++++++++++++++++++++"
echo ""
read -rp 'Set the mongo root user: ' mongo_root_user
done
}
urlencode() {
# urlencode <string>
local old_lc_collate="$LC_COLLATE"
LC_COLLATE=C
local length="${#1}"
for (( i = 0; i < length; i++ )); do
local c="${1:i:1}"
case $c in
[a-zA-Z0-9.~_-]) printf "$c" ;;
*) printf '%%%02X' "'$c" ;;
esac
done
LC_COLLATE="$old_lc_collate"
}
generate_password() {
# Picked up the following method of generation from : https://gist.github.com/earthgecko/3089509
LC_CTYPE=C tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 13 | head -n 1
}
confirm() {
local default="$1" # Should be `y` or `n`.
local prompt="$2"
local options="y/N"
if [[ $default == y || $default == Y ]]; then
options="Y/n"
fi
local answer
read -rp "$prompt [$options] " answer
if [[ -z $answer ]]; then
# No answer given, the user just hit the Enter key. Take the default value as the answer.
answer="$default"
else
# An answer was given. This means the user didn't get to hit Enter so the cursor on the same line. Do an empty
# echo so the cursor moves to a new line.
echo
fi
[[ yY =~ $answer ]]
}
echo_contact_support() {
echo "Please contact <support@appsmith.com> with your OS details and version${1:-.}"
}
bye() { # Prints a friendly good bye message and exits the script.
set +o errexit
echo "Please share your email to receive support with the installation"
read -rp 'Email: ' email
curl -s --location --request POST 'https://hook.integromat.com/dkwb6i52am93pi30ojeboktvj32iw0fa' \
--header 'Content-Type: text/plain' \
--data-raw '{
"userId": "'"$APPSMITH_INSTALLATION_ID"'",
"event": "Installation Support",
"data": {
"os": "'"$os"'",
"email": "'"$email"'",
"platform": "k8s"
}
}'
echo -e "\nExiting for now. Bye! \U1F44B\n"
exit 1
}
download_template_file() {
templates_dir="$(mktemp -d)"
template_endpoint="https://raw.githubusercontent.com/appsmithorg/appsmith/master"
mkdir -p "$templates_dir"
(
cd "$templates_dir"
curl --remote-name-all --silent --show-error -o appsmith-configmap.yaml.sh \
"$template_endpoint/deploy/k8s/scripts/appsmith-configmap.yaml.sh"
curl --remote-name-all --silent --show-error -o appsmith-ingress.yaml.sh \
"$template_endpoint/deploy/k8s/scripts/appsmith-ingress.yaml.sh"
curl --remote-name-all --silent --show-error -o encryption-configmap.yaml.sh \
"$template_endpoint/deploy/k8s/scripts/encryption-configmap.yaml.sh"
curl --remote-name-all --silent --show-error -o mongo-configmap.yaml.sh \
"$template_endpoint/deploy/k8s/scripts/mongo-configmap.yaml.sh"
curl --remote-name-all --silent --show-error -o nginx-configmap.yaml \
"$template_endpoint/deploy/k8s/scripts/nginx-configmap.yaml"
if [[ "$ssl_enable" == "true" ]]; then
curl --remote-name-all --silent --show-error -o issuer-template.yaml.sh\
"$template_endpoint/deploy/k8s/scripts/issuer-template.yaml.sh"
fi
)
(
cd "$install_dir"
curl --remote-name-all --silent --show-error -o backend-template.yaml \
"$template_endpoint/deploy/k8s/templates/backend-template.yaml"
curl --remote-name-all --silent --show-error -o frontend-template.yaml \
"$template_endpoint/deploy/k8s/templates/frontend-template.yaml"
if [[ "$fresh_installation" == "true" ]]; then
curl --remote-name-all --silent --show-error -o mongo-template.yaml \
"$template_endpoint/deploy/k8s/templates/mongo-template.yaml"
fi
curl --remote-name-all --silent --show-error -o redis-template.yaml \
"$template_endpoint/deploy/k8s/templates/redis-template.yaml"
curl --remote-name-all --silent --show-error -o imago-template.yaml\
"$template_endpoint/deploy/k8s/templates/imago-template.yaml"
)
}
deploy_app() {
kubectl apply -f "$install_dir/config-template"
kubectl apply -f "$install_dir"
}
install_certmanager() {
cert_manager_ns=`kubectl get namespace cert-manager --no-headers --output=go-template={{.metadata.name}} --ignore-not-found`
if [ -z "${cert_manager_ns}" ]; then
echo "Installing Cert-manager";
# cert-manager installation document: https://cert-manager.io/docs/installation/kubernetes/
kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.0.3/cert-manager.yaml
sleep 30; # Wait 30s for cert-manger ready
else
echo "Cert-manager already install"
fi
}
wait_for_application_start() {
local timeout=$1
address=$custom_domain
if [[ "$ssl_enable" == "true" ]]; then
protocol="https"
else
protocol="http"
fi
# The while loop is important because for-loops don't work for dynamic values
while [[ $timeout -gt 0 ]]; do
if [[ $address == "" || $address == null ]]; then
address=`kubectl get ingress appsmith-ingress -o json | jq -r '.status.loadBalancer.ingress[0].ip'`
fi
status_code="$(curl -s -o /dev/null -w "%{http_code}" $protocol://$address/api/v1 || true)"
if [[ status_code -eq 401 ]]; then
break
else
echo -ne "Waiting for all containers to start. This check will timeout in $timeout seconds...\r\c"
fi
((timeout--))
sleep 1
done
echo ""
}
echo -e "\U1F44B Thank you for trying out Appsmith! "
echo ""
# Checking OS and assigning package manager
desired_os=0
os=""
echo -e "\U1F575 Detecting your OS"
check_os
APPSMITH_INSTALLATION_ID=$(curl -s 'https://api64.ipify.org')
# Run bye if failure happens
trap bye EXIT
curl -s --location --request POST 'https://hook.integromat.com/dkwb6i52am93pi30ojeboktvj32iw0fa' \
--header 'Content-Type: text/plain' \
--data-raw '{
"userId": "'"$APPSMITH_INSTALLATION_ID"'",
"event": "Installation Started",
"data": {
"os": "'"$os"'",
"platform": "k8s"
}
}'
if [[ $desired_os -eq 0 ]];then
echo ""
echo "This script is currently meant to install Appsmith on Mac OS X | Ubuntu machines."
echo_contact_support " if you wish to extend this support."
bye
else
echo "You're on an OS that is supported by this installation script."
echo ""
fi
if [[ $EUID -eq 0 ]]; then
echo "+++++++++++ ERROR ++++++++++++++++++++++"
echo "Please do not run this script as root/sudo."
echo "++++++++++++++++++++++++++++++++++++++++"
echo_contact_support
bye
fi
# Check for kubernetes setup
check_k8s_setup
read -rp 'Installation Directory [appsmith]: ' install_dir
install_dir="${install_dir:-appsmith}"
if [[ $install_dir != /* ]]; then
# If it's not an absolute path, prepend current working directory to it, to make it an absolute path.
install_dir="$PWD/$install_dir"
fi
echo "Installing Appsmith to '$install_dir'."
mkdir -p "$install_dir"
echo ""
if confirm y "Is this a fresh installation?"; then
fresh_installation="true"
echo "Appsmith needs to create a MongoDB instance."
mongo_protocol="mongodb://"
mongo_host="mongo-service"
mongo_database="appsmith"
# We invoke functions to read the mongo credentials from the user because they MUST be non-empty
read_mongo_username
read_mongo_password
# Since the mongo was automatically setup, this must be the first time installation. Generate encryption credentials for this scenario
auto_generate_encryption="true"
else
fresh_installation="false"
read -rp 'Enter your current mongo db protocol (mongodb:// || mongodb+srv://): ' mongo_protocol
read -rp 'Enter your current mongo db host: ' mongo_host
read -rp 'Enter your current mongo root user: ' mongo_root_user
read -srp 'Enter your current mongo password: ' mongo_root_password
echo ""
read -rp 'Enter your current mongo database name: ' mongo_database
# It is possible that this isn't the first installation.
echo ""
# In this case be more cautious of auto generating the encryption keys. Err on the side of not generating the encryption keys
if confirm y "Do you have any existing data in the database?"; then
auto_generate_encryption="false"
else
auto_generate_encryption="true"
fi
fi
echo ""
# urlencoding the Mongo username and password
encoded_mongo_root_user=$(urlencode "$mongo_root_user")
encoded_mongo_root_password=$(urlencode "$mongo_root_password")
encryptionEnv="$install_dir/config-template/encryption-configmap.yaml"
if test -f "$encryptionEnv"; then
echo "CAUTION : This isn't your first time installing appsmith. Encryption password and salt already exist. Do you want to override this? NOTE: Overwriting the existing salt and password would lead to you losing access to sensitive information encrypted using the same"
echo "1) No. Conserve the older encryption password and salt and continue"
echo "2) Yes. Overwrite the existing encryption (NOT SUGGESTED) with autogenerated encryption password and salt"
echo "3) Yes. Overwrite the existing encryption (NOT SUGGESTED) with manually entering the encryption password and salt"
read -rp 'Enter option number [1]: ' overwrite_encryption
overwrite_encryption=${overwrite_encryption:-1}
auto_generate_encryption="false"
if [[ $overwrite_encryption -eq 1 ]];then
setup_encryption="false"
elif [[ $overwrite_encryption -eq 2 ]];then
setup_encryption="true"
auto_generate_encryption="true"
elif [[ $overwrite_encryption -eq 3 ]];then
setup_encryption="true"
auto_generate_encryption="false"
fi
else
setup_encryption="true"
fi
if [[ "$setup_encryption" = "true" ]];then
if [[ "$auto_generate_encryption" = "false" ]];then
echo "Please enter the salt and password found in the encyption.env file of your previous appsmith installation "
read -rp 'Enter your encryption password: ' user_encryption_password
read -rp 'Enter your encryption salt: ' user_encryption_salt
elif [[ "$auto_generate_encryption" = "true" ]]; then
user_encryption_password=$(generate_password)
user_encryption_salt=$(generate_password)
fi
fi
echo ""
if confirm n "Do you have a custom domain that you would like to link? (Only for cloud installations)"; then
read -rp 'Enter the domain or subdomain on which you want to host appsmith (example.com / app.example.com): ' custom_domain
curl -s --location --request POST 'https://hook.integromat.com/dkwb6i52am93pi30ojeboktvj32iw0fa' \
--header 'Content-Type: text/plain' \
--data-raw '{
"userId": "'"$APPSMITH_INSTALLATION_ID"'",
"event": "Installation Custom Domain",
"data": {
"os": "'"$os"'",
"platform": "k8s"
}
}'
echo ""
echo "+++++++++++ IMPORTANT PLEASE READ ++++++++++++++++++++++"
echo "Please update your DNS records with your domain registrar"
echo "You can read more about this in our Documentation"
echo "https://docs.appsmith.com/v/v1.1/quick-start#custom-domains"
echo "+++++++++++++++++++++++++++++++++++++++++++++++"
echo ""
echo "Would you like to provision an SSL certificate for your custom domain / subdomain?"
if confirm y '(Your DNS records must be updated for us to proceed)'; then
ssl_enable="true"
fi
read -rp 'Enter email address to create SSL certificate: (Optional, but strongly recommended): ' user_email
if confirm n 'Do you want to create certificate in staging mode (which is used for dev purposes and is not subject to rate limits)?'; then
issuer_server="https://acme-staging-v02.api.letsencrypt.org/directory"
else
issuer_server="https://acme-v02.api.letsencrypt.org/directory"
fi
fi
echo ""
echo "Downloading the configuration templates..."
download_template_file
echo ""
echo "Generating the configuration files from the templates"
cd "$templates_dir"
mkdir -p "$install_dir/config-template"
bash "$templates_dir/appsmith-configmap.yaml.sh" "$mongo_protocol" "$mongo_host" "$encoded_mongo_root_user" "$encoded_mongo_root_password" "$mongo_database" > appsmith-configmap.yaml
if [[ "$setup_encryption" == "true" ]]; then
bash "$templates_dir/encryption-configmap.yaml.sh" "$user_encryption_password" "$user_encryption_salt" > encryption-configmap.yaml
overwrite_file "config-template" "encryption-configmap.yaml"
fi
if [[ -n $custom_domain ]]; then
bash "$templates_dir/appsmith-ingress.yaml.sh" "$custom_domain" "$ssl_enable"> ingress-template.yaml
else
bash "$templates_dir/appsmith-ingress.yaml.sh" "" "$ssl_enable" > ingress-template.yaml
fi
if [[ "$ssl_enable" == "true" ]]; then
echo "$user_email"
echo "$issuer_server"
bash "$templates_dir/issuer-template.yaml.sh" "$user_email" "$issuer_server" > issuer-template.yaml
overwrite_file "" "issuer-template.yaml"
fi
overwrite_file "config-template" "nginx-configmap.yaml"
overwrite_file "config-template" "appsmith-configmap.yaml"
overwrite_file "" "ingress-template.yaml"
if [[ "$fresh_installation" == "true" ]]; then
bash "$templates_dir/mongo-configmap.yaml.sh" "$mongo_root_user" "$mongo_root_password" "$mongo_database" > mongo-configmap.yaml
overwrite_file "config-template" "mongo-configmap.yaml"
fi
echo ""
echo "Deploy Appmisth on your cluster"
echo ""
if [[ "$ssl_enable" == "true" ]]; then
install_certmanager
else
echo "No domain found. Skipping generation of SSL certificate."
fi
echo ""
deploy_app
wait_for_application_start 60
echo ""
if [[ $status_code -ne 401 ]]; then
echo "+++++++++++ ERROR ++++++++++++++++++++++"
echo "The containers didn't seem to start correctly. Please run the following command to check pods that may have errored out:"
echo ""
echo -e "kubectl get pods"
echo "For troubleshooting help, please reach out to us via our Discord server: https://discord.com/invite/rBTTVJp"
echo "++++++++++++++++++++++++++++++++++++++++"
echo ""
echo "Please share your email to receive help with the installation"
read -rp 'Email: ' email
curl -s --location --request POST 'https://hook.integromat.com/dkwb6i52am93pi30ojeboktvj32iw0fa' \
--header 'Content-Type: text/plain' \
--data-raw '{
"userId": "'"$APPSMITH_INSTALLATION_ID"'",
"event": "Installation Support",
"data": {
"os": "'"$os"'",
"email": "'"$email"'",
"platform": "k8s"
}
}'
else
curl -s --location --request POST 'https://hook.integromat.com/dkwb6i52am93pi30ojeboktvj32iw0fa' \
--header 'Content-Type: text/plain' \
--data-raw '{
"userId": "'"$APPSMITH_INSTALLATION_ID"'",
"event": "Installation Success",
"data": {
"os": "'"$os"'",
"platform": "k8s"
}
}'
echo "+++++++++++ SUCCESS ++++++++++++++++++++++++++++++"
echo "Your installation is complete!"
echo ""
if [[ -z $custom_domain ]]; then
echo "Your application is running on '$protocol://$address'."
else
echo "Your application is running on '$protocol://$custom_domain'."
fi
echo ""
echo "+++++++++++++++++++++++++++++++++++++++++++++++++"
echo ""
echo "Need help Getting Started?"
echo "Join our Discord server https://discord.com/invite/rBTTVJp"
echo "Please share your email to receive support & updates about appsmith!"
read -rp 'Email: ' email
curl -s --location --request POST 'https://hook.integromat.com/dkwb6i52am93pi30ojeboktvj32iw0fa' \
--header 'Content-Type: text/plain' \
--data-raw '{
"userId": "'"$APPSMITH_INSTALLATION_ID"'",
"event": "Identify Successful Installation",
"data": {
"os": "'"$os"'",
"email": "'"$email"'",
"platform": "k8s"
}
}'
fi
echo -e "\nPeace out \U1F596\n"

View File

@ -0,0 +1,31 @@
set -o nounset
mongo_protocol="$1"
mongo_host="$2"
encoded_mongo_root_user="$3"
encoded_mongo_root_password="$4"
mongo_db="$5"
cat<<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: application-config
data:
APPSMITH_MAIL_ENABLED: "false"
# APPSMITH_MAIL_FROM: ""
# APPSMITH_REPLY_TO: ""
# APPSMITH_MAIL_HOST: ""
# APPSMITH_MAIL_PORT: ""
# APPSMITH_MAIL_SMTP_TLS_ENABLED: ""
# APPSMITH_MAIL_USERNAME: ""
# APPSMITH_MAIL_PASSWORD: ""
# APPSMITH_MAIL_SMTP_AUTH: ""
# APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ""
# APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET: ""
# APPSMITH_OAUTH2_GITHUB_CLIENT_ID: ""
# APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET: ""
APPSMITH_GOOGLE_MAPS_API_KEY: ""
APPSMITH_REDIS_URL: redis://redis-service:6379
APPSMITH_MONGODB_URI: $mongo_protocol$encoded_mongo_root_user:$encoded_mongo_root_password@$mongo_host/$mongo_db?retryWrites=true&authSource=admin
EOF

View File

@ -0,0 +1,98 @@
set -o nounset
custom_domain="$1"
ssl_enable="$2"
if [[ "$ssl_enable" == "true" ]]; then
cat <<EOF
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: appsmith-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/issuer: "letsencrypt-production"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
tls:
- hosts:
- $custom_domain
secretName: lego-tls
backend:
serviceName: "appsmith-editor"
servicePort: 80
rules:
- host: $custom_domain
http:
paths:
- path: /api
pathType: Prefix
backend:
serviceName: appsmith-backend-service
servicePort: 8080
- path: /oauth
pathType: Prefix
backend:
serviceName: appsmith-backend-service
servicePort: 8080
- path: /login
pathType: Prefix
backend:
serviceName: appsmith-backend-service
servicePort: 8080
- path: /static
pathType: Prefix
backend:
serviceName: appsmith-editor
servicePort: 80
- path: /
pathType: Prefix
backend:
serviceName: appsmith-editor
servicePort: 80
EOF
else
cat << EOF
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: appsmith-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
backend:
serviceName: "appsmith-editor"
servicePort: 80
rules:
- host: $custom_domain
http:
paths:
- path: /api
pathType: Prefix
backend:
serviceName: appsmith-backend-service
servicePort: 8080
- path: /oauth
pathType: Prefix
backend:
serviceName: appsmith-backend-service
servicePort: 8080
- path: /login
pathType: Prefix
backend:
serviceName: appsmith-backend-service
servicePort: 8080
- path: /static
pathType: Prefix
backend:
serviceName: appsmith-editor
servicePort: 80
- path: /
pathType: Prefix
backend:
serviceName: appsmith-editor
servicePort: 80
EOF
fi

View File

@ -0,0 +1,14 @@
set -o nounset
user_encryption_password="$1"
user_encryption_salt="$2"
cat<<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: encryption-config
data:
APPSMITH_ENCRYPTION_PASSWORD: $user_encryption_password
APPSMITH_ENCRYPTION_SALT: $user_encryption_salt
EOF

View File

@ -0,0 +1,48 @@
set -o nounset
user_email="$1"
issuer_server="$2"
if [[ -z $user_email ]]; then
cat <<EOF
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-production
spec:
acme:
# The ACME server URL
server: $issuer_server
# Email address used for ACME registration
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-production
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: nginx
EOF
else
cat <<EOF
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-production
spec:
acme:
# The ACME server URL
server: $issuer_server
# Email address used for ACME registration
email: $user_email
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-production
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: nginx
EOF
fi

View File

@ -0,0 +1,17 @@
set -o nounset
mongo_root_user="$1"
mongo_root_password="$2"
mongo_database="$3"
cat <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: mongo-config
data:
MONGO_INITDB_DATABASE: $mongo_database
MONGO_INITDB_ROOT_USERNAME: $mongo_root_user
MONGO_INITDB_ROOT_PASSWORD: $mongo_root_password
EOF

View File

@ -0,0 +1,43 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config-template
data:
nginx.conf.template: "
server {
listen 80;
client_max_body_size 10m;
gzip on;
root /var/www/appsmith;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
location / {
try_files $uri /index.html =404;
alias /var/www/appsmith/;
sub_filter __APPSMITH_SENTRY_DSN__ '${APPSMITH_SENTRY_DSN}';
sub_filter __APPSMITH_SMART_LOOK_ID__ '${APPSMITH_SMART_LOOK_ID}';
sub_filter __APPSMITH_OAUTH2_GOOGLE_CLIENT_ID__ '${APPSMITH_OAUTH2_GOOGLE_CLIENT_ID}';
sub_filter __APPSMITH_OAUTH2_GITHUB_CLIENT_ID__ '${APPSMITH_OAUTH2_GITHUB_CLIENT_ID}';
sub_filter __APPSMITH_MARKETPLACE_ENABLED__ '${APPSMITH_MARKETPLACE_ENABLED}';
sub_filter __APPSMITH_SEGMENT_KEY__ '${APPSMITH_SEGMENT_KEY}';
sub_filter __APPSMITH_OPTIMIZELY_KEY__ '${APPSMITH_OPTIMIZELY_KEY}';
sub_filter __APPSMITH_ALGOLIA_API_ID__ '${APPSMITH_ALGOLIA_API_ID}';
sub_filter __APPSMITH_ALGOLIA_SEARCH_INDEX_NAME__ '${APPSMITH_ALGOLIA_SEARCH_INDEX_NAME}';
sub_filter __APPSMITH_ALGOLIA_API_KEY__ '${APPSMITH_ALGOLIA_API_KEY}';
sub_filter __APPSMITH_CLIENT_LOG_LEVEL__ '${APPSMITH_CLIENT_LOG_LEVEL}';
sub_filter __APPSMITH_GOOGLE_MAPS_API_KEY__ '${APPSMITH_GOOGLE_MAPS_API_KEY}';
sub_filter __APPSMITH_TNC_PP__ '${APPSMITH_TNC_PP}';
sub_filter __APPSMITH_VERSION_ID__ '${APPSMITH_VERSION_ID}';
sub_filter __APPSMITH_VERSION_RELEASE_DATE__ '${APPSMITH_VERSION_RELEASE_DATE}';
sub_filter __APPSMITH_INTERCOM_APP_ID__ '${APPSMITH_INTERCOM_APP_ID}';
sub_filter __APPSMITH_MAIL_ENABLED__ '${APPSMITH_MAIL_ENABLED}';
}
location /f {
proxy_pass https://cdn.optimizely.com/;
}
}"

View File

@ -0,0 +1,41 @@
apiVersion: v1
kind: Service
metadata:
name: appsmith-backend-service
labels:
app: appsmith-backend-service
spec:
selector:
app: appsmith-internal-server
type: NodePort
ports:
- port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: appsmith-internal-server
name: appsmith-internal-server
spec:
replicas: 1
selector:
matchLabels:
app: appsmith-internal-server
template:
metadata:
labels:
app: appsmith-internal-server
spec:
containers:
- envFrom:
- configMapRef:
name: application-config
- configMapRef:
name: encryption-config
image: appsmith/appsmith-server:latest
name: appsmith-internal-server
ports:
- containerPort: 8080

View File

@ -0,0 +1,41 @@
apiVersion: v1
kind: Service
metadata:
name: appsmith-editor
spec:
selector:
app: appsmith-editor
ports:
- port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: appsmith-editor
spec:
selector:
matchLabels:
app: appsmith-editor
replicas: 1
template:
metadata:
labels:
app: appsmith-editor
spec:
containers:
- name: nginx
image: appsmith/appsmith-editor
ports:
- containerPort: 80
envFrom:
- configMapRef:
name: application-config
volumeMounts:
- name: nginx-config-template
mountPath: /nginx.conf.template
subPath: nginx.conf.template
volumes:
- name: nginx-config-template
configMap:
name: nginx-config-template

View File

@ -0,0 +1,77 @@
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: imago
namespace: default
spec:
schedule: "0 * * * *"
concurrencyPolicy: Forbid
jobTemplate:
spec:
template:
metadata:
labels:
k8s-app: imago
spec:
restartPolicy: Never
serviceAccount: imago
serviceAccountName: imago
containers:
- name: imago
image: philpep/imago
imagePullPolicy: Always
args: ["--update"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: imago
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: imago
rules:
- apiGroups:
- ""
- apps
resources:
- pods
- replicasets
- statefulsets
verbs:
- list
- apiGroups:
- ""
- batch
resources:
- cronjobs
verbs:
- get
- list
- update
- apiGroups:
- ""
- apps
resources:
- daemonsets
- deployments
- statefulsets
verbs:
- get
- list
- update
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: imago
roleRef:
kind: ClusterRole
name: imago
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: imago
namespace: default

View File

@ -0,0 +1,50 @@
apiVersion: v1
kind: Service
metadata:
name: mongo-service
labels:
name: mongo
spec:
type: NodePort
ports:
- port: 27017
targetPort: 27017
protocol: TCP
selector:
role: mongo
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mongo-statefulset
spec:
selector:
matchLabels:
role: mongo
serviceName: "mongo-service"
replicas: 1
template:
metadata:
labels:
role: mongo
spec:
terminationGracePeriodSeconds: 10
containers:
- name: mongo
image: mongo
ports:
- containerPort: 27017
volumeMounts:
- name: mongo-persistent-storage
mountPath: /data/db
envFrom:
- configMapRef:
name: mongo-config
volumeClaimTemplates:
- metadata:
name: mongo-persistent-storage
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 10Gi

View File

@ -0,0 +1,46 @@
apiVersion: v1
kind: Service
metadata:
name: redis-service
labels:
name: redis
spec:
type: NodePort
ports:
- port: 6379
targetPort: 6379
selector:
role: redis
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis-statefulset
spec:
selector:
matchLabels:
role: redis
serviceName: "redis-service"
replicas: 1
template:
metadata:
labels:
role: redis
spec:
terminationGracePeriodSeconds: 10
containers:
- name: redis
image: redis
ports:
- containerPort: 6379
volumeMounts:
- name: redis-persistent-storage
mountPath: /data
volumeClaimTemplates:
- metadata:
name: redis-persistent-storage
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 5Gi