此教學將會使用到 AWS ECR 將建制的 docker image 推到 aws 的 private docker registry, 並且最後會建置一個 ALB Laravel application 起來。
因為我們會將 docker image 推送到 ECR, 所以我們要先建立 ECR
- 進入到 AWS ECR
2. 新增 docker repository
3. 選擇 private 且輸入可以識別的 repository name, 都輸入好後按下 create 即可在 ecr 列表上看到
4. 進入所建立的 ECR, 點選 push command 可以看到上傳 image 到 ECR 的指令
首先我們先建置一個 nginx 相關的服務起來。
- 建置 nginx Dockerfile
FROM nginx:latest
COPY ./nginx/config/nginx.conf /etc/nginx/conf.d/web.conf
COPY ./data/index.php /app/index.php
2. ./config/nginx.conf
server {
listen 80;
server_name <server name>;
root /app;
index index.php index.html
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ .php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+.php)(/.+)$;
fastcgi_pass php-service:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
3. index.php
<!DOCTYPE html>
<html>
<body style="background-color:rgb(217, 250, 210);">
<h1>Welcome to Stack Simplify</h1>
<h3>AWS EKS Master Class - Integration with ECR Registry</h3>
<h3><?php echo 'php version: '. phpversion(); ?></h3>
</body>
</html>
index.html 的用途主要是等等先測試看看 nginx service 是否有建置成功所做的範本,所以到時可以移除。
4. build nginx docker image
cd <nginx dockerfile 所在的位置>
docker build --tag <aws ecr tag> -f <nginx Dockerfile 的檔案名稱> .
5. 建置好後可以透過 docker images 查看是否有 build image 出來
docker images
6. 將 docker image 推送到 ecr 使用上面 ecr push command 的步驟, 依照步驟做完後即可在 ECR 看到鎖推送的 image
7. 因為 EKS 要從 ECR pull image 下來所以需要設定 imagePullSecret
# 取得 ecr token
TOKEN=$(aws ecr get-login-password --region <region>)
kubectl create secret docker-registry regcred --docker-server=<ecr> --docker-username=AWS --docker-password=$TOKEN
參考資料如下:
8. 建議完後即可以在 secret 看到所建立的 regcred
kubectl get secret -o wide
透過以下指令可以查看詳細內容
kubectl get secret regcred --output=yaml
9. deployments/nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
labels:
app: web
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
name: web
labels:
app: web
spec:
containers:
- image: <ecr>
name: nginx
ports:
- containerPort: 80
imagePullSecrets:
- name: regcred
10. 套用 deployment.yml 以及查看所建立的 pods
kubectl apply -f <deployment file>
kubectl get pods -o wide
11. 建立 nginx service.yml
apiVersion: v1
kind: Service
metadata:
name: web-service
labels:
web: service
spec:
# 建立 ALB 且 annotations 為 instance 的話記得要設定為 NodePort
type: NodePort
selector:
app: web
ports:
- port: 80
protocol: TCP
targetPort: 80
12. 套用 service.yml 且查看 service
kubectl apply -f <service yml file>
kubectl get svc
建立 php 相關的 pod
在建立 php 相關的 pod 前記得也需要為 php 新增一個 private registry 在 ECR 上。
php Dockerfile
FROM php:8.1-fpm
COPY ./data/index.php /app/index.php
用以下指令 build php docker image
docker build --tag <php ecr repository> -f <docker file> .
php_deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-deployment
labels:
app: php
spec:
replicas: 1
selector:
matchLabels:
app: php
template:
metadata:
name: app-deployment
labels:
app: php
spec:
containers:
- name: php81-fpm
image: <ecr>/php:latest
ports:
- containerPort: 9000
imagePullSecrets:
- name: regcred
套用 php deployment
kubectl apply -f <php deployment file>
查看 php deployment 是否已建立成功
kubect get pods -o wide
建立 php_service.yml
apiVersion: v1
kind: Service
metadata:
# 在 nginx.conf php-fpm socket 所使用的名稱
name: php-service
labels:
php: service
spec:
selector:
app: php
ports:
- port: 9000
targetPort: 9000
套用 php_service.yml
kubectl apply -f <php service file>
設定 ALB ingresss
緊接著我們要來設定 ALB, 在設定 ALB 之前我們需要安裝所需的套件 helm。
1. 在設定 ingress 之前我們要先安裝 helm, 因為會使用到 aws-load-balancer-controller
brew install helm
安裝完成後按照以下網址的設定進行 role policy 以及安裝步驟
helm install aws-load-balancer-controller eks/aws-load-balancer-controller -n kube-system --set clusterName=<cluster-name>
假如在安裝時沒有指定 service account name 的話記得要在 EKS worker node role 增加以下網址的 policy
https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.7.0/docs/install/iam_policy.json
2. 透過以下指令檢查 aws-load-balancer-controller 是否正常運行
https://docs.aws.amazon.com/zh_tw/eks/latest/userguide/aws-load-balancer-controller.html
3. 我們要使用ALB 因此要建立一個 alb ingress
web-ingress.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
labels:
app: ingress
annotations:
# 啟用 aws alb
kubernetes.io/ingress.class: alb
# 目標為 instance
alb.ingress.kubernetes.io/target-type: instance
# 對外網的 pod 設定, 假如為內部則 internal
alb.ingress.kubernetes.io/scheme: internet-facing
spec:
rules:
- http:
paths:
- backend:
service:
name: web-service
port:
number: 80
path: /
pathType: Prefix
host: <host name>
4. 套用 ingress 並且檢查是否正常
kubectl apply -f <ingress file>
kubectl get ingress -o wide
5. 在 DNS 設定好之後就可以透過 ingress 設定的 host 連進去查看
建置 Laravel 用的 Service
這邊將會把前面使用的 index.php 改為指向 laravel project,首先我們先來修改 php 的 Dockerfile 為如下
Dockerfile
# 引入 composer2.7 image
FROM composer:2.7 as composer
### 環境準備以及一些參數設定
FROM php:8.1-fpm
# 複製 composer image 的 composer binary 到 php image
COPY --from=composer /usr/bin/composer /usr/bin/composer
# 系統更新
RUN apt-get update
# 安裝系統套件
RUN apt-get install -y libzip-dev \
zip unzip wget zlib1g-dev libicu-dev \
libfreetype6-dev libjpeg62-turbo-dev \
libpng-dev
RUN docker-php-ext-configure gd --with-freetype --with-jpeg
RUN docker-php-ext-install -j$(nproc) gd
# 安裝 php 套件
RUN docker-php-ext-install zip pdo pdo_mysql intl opcache
# 使 composer 可以使用 sudo
ENV COMPOSER_ALLOW_SUPERUSER=1
# 複製專案到 app
COPY ./project/k8s-demo /app
# 切換工作目錄
WORKDIR /app
# 安裝套件
RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist
# 產生 vendor/autoload.php
RUN composer dump-autoload
# 修改 storage 權限
RUN chmod -R 777 storage/
# COPY ./data/index.php /app/index.php
php_deployment.yml 相對應的也要修改,因為跟 nginx 一樣改為從 ECR 抓取 image, 且在初始化 container 的時候執行 migrate
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-deployment
labels:
app: php
spec:
replicas: 2
selector:
matchLabels:
app: php
template:
metadata:
name: app-deployment
labels:
app: php
spec:
affinity:
# 選取節點名稱為 web
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: eks.amazonaws.com/nodegroup
operator: In
values:
- web
# 假如 node 裡面的 pod 已經有 app:label 的話則不加入此 node
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: kubernetes.io/hostname
labelSelector:
matchLabels:
app: php
# 在啟服務前先跑 migration
initContainers:
- name: laravel-migration
image: <php ecr image>
command:
- "php"
args:
- "artisan"
- "migrate"
containers:
- name: php81-fpm
image: <php ecr image>
ports:
- containerPort: 9000
imagePullSecrets:
- name: regcred
重新 build php image 以及套用 php_deployment.yml
kubectl apply -f <php deployment file>
因為現在是將 laravel project copy 到 container 內,所以 nginx 的 image 也需要做修改,將 nginx.conf 修改如下
server {
listen 80;
server_name <server name>;
root /app/public;
index index.php index.html
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ .php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+.php)(/.+)$;
fastcgi_pass php-service:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
將 nginx 的 Dockerfile 修改,改為將 php ecr image 的資料複製到 nginx image 裡面
FROM nginx:latest
COPY ./nginx/config/nginx.conf /etc/nginx/conf.d/web.conf
# COPY ./data/index.php /app/index.php
# 將 php image 的資料 copy 到 nginx /app
COPY --from=<php ecr image> /app /app
nginx_deployment 也需要做修改
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
labels:
app: web
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
name: web
labels:
app: web
spec:
affinity:
# 將 pod 加入至 nodegroup 為 web 的節點群中
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: eks.amazonaws.com/nodegroup
operator: In
values:
- web
# 假如 node 裡的 pod 已經有 app:web 的標籤的話則不加 pod 加入此 node
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: kubernetes.io/hostname
labelSelector:
matchLabels:
app: web
containers:
- image: <ecr nginx image>
name: nginx
ports:
- containerPort: 80
imagePullSecrets:
- name: regcred
重新 build nginx image 以及重新套用 nginx_deployment
kubectl apply -f <nginx deployment>
建置 MySQL
因為要使用到 Laravel 所以接下的步驟將會教學如何建置 mysql service。前面的部分我們將 web 相關的服務放在某個 EKS Cluster 裡面,而 mysql 的部分我們為其建立一個 node group 在相同的 EKS Cluster 裡面。
我們先為其 mysql 建置所需的資料庫名稱以及使用者 (ConfigMap)
mysql-config.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-config
labels:
mysql: config
data:
database: web
user: laravel
套用 mysql-config
kubectl apply -f mysql-config.yml
為 Mysql 建置使用者所需的密碼, 而 secret 的編碼為 base64
mysql-secret.yml
apiVersion: v1
kind: Secret
metadata:
name: mysql-secret
labels:
mysql: secret
data:
root-password: cm9vdA==
user-password: bGFyYXZlbA==
為其 mysql 建立所需的 deployment
mysql-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-deployment
labels:
app: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
# 將 mysql 的資源放在名叫 mysql 的 node group
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: eks.amazonaws.com/nodegroup
operator: In
values:
- mysql
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
env:
- name: MYSQL_DATABASE
valueFrom:
configMapKeyRef:
key: database
name: mysql-config
- name: MYSQL_USER
valueFrom:
configMapKeyRef:
key: user
name: mysql-config
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
key: root-password
name: mysql-secret
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
key: user-password
name: mysql-secret
將此 deployment 套用
kubectl apply -f mysql-deployment.yml
為 mysql 建置 service
mysql-service.yml
apiVersion: v1
kind: Service
metadata:
name: mysql-service
labels:
mysql: service
spec:
selector:
app: mysql
ports:
- port: 3306
targetPort: 3306
protocol: TCP
將此 mysql-service.yml 套用
kubectl apply -f mysql-service.yml
都設定完成後直可透過網址看到 Laravel 的 welcome 頁面
建置 Laravel 排程到 node group
建置 cronJob.yml
apiVersion: batch/v1
kind: CronJob
metadata:
name: laravel-schedule
labels:
laravel: schedule
spec:
schedule: "* * * * *"
jobTemplate:
spec:
template:
spec:
affinity:
# 選取節點名稱為 cron
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: eks.amazonaws.com/nodegroup
operator: In
values:
- cron
containers:
- image: <php ecr repository>
name: scheduler
command:
- php
args:
- "artisan"
- "schedule:run"
imagePullSecrets:
- name: regcred
# 先設定為重啟後不會重啟
restartPolicy: Never
套用 cronjob
kubectl apply -f cronJob.yml
此時可以透過 pod 查看 cronJob 是否正常運行
kubectl get pods
參考文件: