Skip to content

Commit

Permalink
Add instructions for running on AWS EKS
Browse files Browse the repository at this point in the history
  • Loading branch information
pnedkov committed Jan 29, 2024
1 parent 9ab6355 commit 61d45cd
Show file tree
Hide file tree
Showing 6 changed files with 339 additions and 0 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,16 @@ cd ipask/
```

</details>

---

<details>
<summary>

## Run on AWS Elastic Kubernetes Service

</summary>

[k8s/README.md](k8s/README.md)

</details>
156 changes: 156 additions & 0 deletions k8s/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# Deploy IP Ask on AWS EKS

Non-comprehensive guide for running IP Ask (or any similar application) in [AWS EKS](https://aws.amazon.com/eks/).

---

## Prerequisites

- AWS account

- AWS user with an access key and [sufficient rights](https://eksctl.io/usage/minimum-iam-policies/)

- Domain with a DNS zone managed by [AWS Route 53](https://aws.amazon.com/route53/)

- Some free time

---

## Software installation and configuration

- Install and configure [awscli](https://aws.amazon.com/cli/)

```sh
$ pacman -S aws-cli-v2
...
$ aws configure
AWS Access Key ID [None]: <your_key_id>
AWS Secret Access Key [None]: <secret_access_key>
Default region name [None]: us-east-1
Default output format [None]: json
$
```

- Install [eksctl](https://eksctl.io/)

```sh
pacman -S eksctl
```

- Install [kubectl](https://kubernetes.io/docs/reference/kubectl/)

```sh
pacman -S kubectl
```

- Request a public SSL/TLS certificate from [AWS ACM](https://aws.amazon.com/certificate-manager/) and validate it with a DNS record

```sh
aws acm request-certificate \
--domain-name ipask.me \
--subject-alternative-names "ipask.me" "*.ipask.me" \
--key-algorithm EC_secp384r1 \
--validation-method DNS \
--idempotency-token 1000 \
--options CertificateTransparencyLoggingPreference=ENABLED
```

Note that `CertificateTransparencyLoggingPreference` must be `enabled`.

- Set and export environment variables that are required for some of the commands later on

```sh
export AWS_EKS_CLUSTER_NAME=my_eks_cluster
export AWS_EKS_REGION=$(aws configure get region)
export AWS_EKS_VERSION=1.28
export AWS_EKS_CIDR="10.250.0.0/16"
export AWS_IAM_CERT_ARN="SSL/TLS certificate's ARN"
export IPASK_VERSION="The latest tag for the prestigen/ipask image"
```

---

## Create AWS EKS cluster

All `AWS_EKS_*` environment variables must be set.

```sh
envsubst < eks-cluster.yaml | eksctl create cluster -f -
```

---

## Test with kubectl

```sh
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-192-168-10-86.ec2.internal Ready <none> 1m v1.28.3-eks-e71965b
ip-192-168-44-82.ec2.internal Ready <none> 1m v1.28.3-eks-e71965b
$
```

---

## Install AWS LB Controller for the Kubernetes cluster

Follow the [official guide](https://docs.aws.amazon.com/eks/latest/userguide/aws-load-balancer-controller.html)

---

## Build and push the container to hub.docker.com

Handled by CI/CD

---

## Deploy the web application to AWS EKS

The `IPASK_VERSION` environment variable must be set.

```sh
envsubst < k8s/ipask.yaml | kubectl apply -f -
```

---

## Create the K8s Ingress resource(s) and the AWS Application Load Balancer

The `AWS_IAM_CERT_ARN` environment variable must be set.

Choose option `A` **_or_** `B`.

- (Option A): All HTTP requests are automatically redirected to HTTPS

```sh
envsubst < alb-ingress.yaml | kubectl apply -f -
```

Note: Due to the fact that `curl` does not automatically follow the new location when the server returns 301, it must be supplied with either the protocol (`https://`) or the `-L` flag:

```sh
curl -L ipask.me
curl https://ipask.me
```

- (Option B): All HTTP requests except the ones coming from `curl` are redirected to HTTPS

```sh
envsubst < alb-ingress-curl-workaround.yaml | kubectl apply -f -
```

With this solution, the HTTP-to-HTTPS redirection is disabled for `curl`, which is why the following command will work but the communication will be unencrypted:

```sh
curl ipask.me
```

`wget` on the other hand automatically initiates a new connection to the new HTTPS location provided in the `301` response:

```sh
wget -qO - ipask.me
```

---

## Create DNS "A" record that points to the Application Load Balancer
63 changes: 63 additions & 0 deletions k8s/alb-ingress-curl-workaround.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ipask-ingress
annotations:
alb.ingress.kubernetes.io/group.name: ipask-ingress-group
alb.ingress.kubernetes.io/group.order: "0"
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}]'
alb.ingress.kubernetes.io/backend-protocol: "HTTP"
alb.ingress.kubernetes.io/actions.bypass-ssl: >
{"type":"forward", "forwardConfig":{"targetGroups":[{"serviceName":"ipask-svc", "servicePort":"8080", "weight":1}]}}
alb.ingress.kubernetes.io/conditions.bypass-ssl: >
[{"field":"http-header", "httpHeaderConfig":{"httpHeaderName":"User-Agent", "values":["curl/*"]}}]
alb.ingress.kubernetes.io/actions.redirect-to-https: >
{"Type":"redirect","RedirectConfig":{"protocol":"HTTPS","port":"443","statusCode":"HTTP_301"}}
spec:
ingressClassName: "alb"
rules:
- host: ipask.me
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: bypass-ssl
port:
name: use-annotation
- path: /
pathType: Prefix
backend:
service:
name: redirect-to-https
port:
name: use-annotation
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ipask-ingress-secure
annotations:
alb.ingress.kubernetes.io/group.name: ipask-ingress-group
alb.ingress.kubernetes.io/group.order: "1"
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS": 443}]'
alb.ingress.kubernetes.io/backend-protocol: "HTTP"
alb.ingress.kubernetes.io/certificate-arn: ${AWS_IAM_CERT_ARN}
spec:
ingressClassName: "alb"
rules:
- host: ipask.me
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ipask-svc
port:
number: 8080
24 changes: 24 additions & 0 deletions k8s/alb-ingress.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ipask-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
alb.ingress.kubernetes.io/backend-protocol: "HTTP"
alb.ingress.kubernetes.io/ssl-redirect: "443"
alb.ingress.kubernetes.io/certificate-arn: ${AWS_IAM_CERT_ARN}
spec:
ingressClassName: "alb"
rules:
- host: ipask.me
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ipask-svc
port:
number: 8080
34 changes: 34 additions & 0 deletions k8s/eks-cluster.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
name: ${AWS_EKS_CLUSTER_NAME}
region: ${AWS_EKS_REGION}
version: "${AWS_EKS_VERSION}"

kubernetesNetworkConfig:
IpFamily: ipv4
serviceIPv4CIDR: ${AWS_EKS_CIDR}

iam:
withOIDC: true

managedNodeGroups:
- name: ng1
instanceType: t3.small
desiredCapacity: 2
minSize: 2
maxSize: 2
volumeSize: 10
volumeType: "gp3"
volumeEncrypted: true
volumeIOPS: 3000
volumeThroughput: 125
labels: { role: workers }
tags:
nodegroup-role: worker
#privateNetworking: true
# ssh:
# allow: true
# publicKeyName: myPublicKeyName
49 changes: 49 additions & 0 deletions k8s/ipask.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ipask
#labels:
# app: ipask
spec:
replicas: 2
selector:
matchLabels:
app: ipask
revisionHistoryLimit: 5
progressDeadlineSeconds: 300
minReadySeconds: 10
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
template:
metadata:
labels:
app: ipask
spec:
containers:
- name: ipask-ctr
image: prestigen/ipask:${IPASK_VERSION}
ports:
- containerPort: 8080
imagePullPolicy: Always
env:
- name: IPASK_PROD
value: "true"
- name: GEOIP
value: "true"
- name: REVERSE_DNS_LOOKUP
value: "true"
---
apiVersion: v1
kind: Service
metadata:
name: ipask-svc
spec:
type: ClusterIP
ports:
- port: 8080
targetPort: 8080
selector:
app: ipask

0 comments on commit 61d45cd

Please sign in to comment.