Skip to main content

Prepare for Kubernetes (K8)

Prerequisite​

  • a K8 cluster, whether it is on a cloud service provider such as linode, gcp, aws, or if you provision it entirely on your own servers, or on local pc using Minicube or others.
  • Kubectl installed on your local machine (to handle work with the k8 cluster)
  • configuring kubectl to your cluster
  • dockerized Laravel
  • a redis instance
  • s3 buckets
  • deployment files

Cancel file system dependencies​

Move all images and media to S3, follow the tutorial​

follow this guide https://wiki.6degrees.com.sa/docs/laravel/migrate-to-s3

Cancel other filesystem dependencies​

  • Move logging to stdout so you can see it using kubectl logs in config/logging.php add:

      'stdout' => [
    'driver' => 'monolog',
    'level' => env('LOG_LEVEL', 'debug'),
    'handler' => StreamHandler::class,
    'formatter' => env('LOG_STDOUT_FORMATTER'),
    'with' => [
    'stream' => 'php://stdout',
    ],
    ],

    then, set LOG_CHANNEL to stdout in configMap, secret (.env)

  • install predis composer require predis/predis adjust configmap, secret or .env

      REDIS_CLIENT: "predis"
    REDIS_PREFIX: "yourappname-prod_"
    REDIS_HOST: "redis.redis.svc.cluster.local" # for k8 cluster
    REDIS_PORT: "6379"
  • Make caching driver redis

    CACHE_DRIVER: "redis"
  • Make session driver redis

    SESSION_DRIVER: "redis"

now you have a floating flying larval, one more thing to make things sweet.

Enhance dockerization​

instead of having php-fpm and nginx (reverse proxy) on separate images, so you will have the need to have a shared volume between them, or a pvc, you can use an image that combines both, the reverse proxy and the php-fpm such as the ones here https://serversideup.net/open-source/docker-php, thus, you will only need one deployment, one service, one ingress.

Env file​

for Environment variables, since we use Valut by Hashicorp, you will need to split the env vars to two k8 manifests, one is a configMap, for env variables that are not secret, and one externalSecrets (secrets) so it will pull it from vault.

and that's it,

below is a sample for all the yaml files needed for k8, and with how to apply them manually. we prefer using argocd for deployment, so, store them in a separate repo, or in the same app repo in a k8s folder, then, add that repo folder in argocd so it will handle sync and deployment automatically.

Manifsets​

dployment.yaml​

apiVersion: apps/v1
kind: Deployment
metadata:
name: almoajil-prod-larvel
namespace: almoajil-prod
labels:
app: almoajil-prod-larvel
spec:
replicas: 1
selector:
matchLabels:
app: almoajil-prod-larvel
template:
metadata:
labels:
app: almoajil-prod-larvel
spec:
imagePullSecrets:
- name: ghcr-secret
containers:
- name: almoajil-prod-larvel
image: "ghcr.io/moajil-project/php_laravel_cms:latest"
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: almoajil-prod-configmap
- secretRef:
name: almoajil-prod-secrets

service.yaml​

apiVersion: v1
kind: Service
metadata:
name: almoajil-prod-laravel
namespace: almoajil-prod
spec:
selector:
app: almoajil-prod-larvel
ports:
- protocol: TCP
port: 8080
targetPort: 8080

ingress.yaml​

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: almoajil-prod-ingress
namespace: almoajil-prod
annotations:
cert-manager.io/cluster-issuer: http01-clusterissuer
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- almoajilhospitality.com
secretName: almoajil-prod-tls
rules:
- host: almoajilhospitality.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: almoajil-prod-laravel
port:
number: 8080

configMap.yaml​

apiVersion: v1
kind: ConfigMap
metadata:
name: almoajil-prod-configmap
namespace: almoajil-prod
data:
APP_URL: "https://almoajilhospitality.com/"
APP_NAME: "Almoajil"
APP_ENV: "production"
APP_DEBUG: "false"
ASSET_URL: "/"

FORCE_HTTPS: "true"

LOG_CHANNEL: "stdout" # k8 compatible
LOG_DEPRECATIONS_CHANNEL: "null"
LOG_LEVEL: "debug"

DB_CONNECTION: "mysql"

REDIS_CLIENT: "predis"
REDIS_PREFIX: "deets-prod_"
REDIS_HOST: "redis.redis.svc.cluster.local"
REDIS_PORT: "6379"

BROADCAST_DRIVER: "log"
CACHE_DRIVER: "redis"
QUEUE_CONNECTION: "sync"

SESSION_DRIVER: "redis" # k8 compatible
SESSION_LIFETIME: "120"

MEMCACHED_HOST: "memcached"

MAIL_MAILER: "smtp"
MAIL_PORT: "587"
MAIL_ENCRYPTION: "tls"

FILESYSTEM_DRIVER: "s3"
FILESYSTEM_DISK: "s3"
FILAMENT_FILESYSTEM_DRIVER: "s3"
MEDIA_DISK: "s3"

AWS_DEFAULT_REGION: "us-east-1"
AWS_BUCKET: "almoajil-prod"
AWS_USE_PATH_STYLE_ENDPOINT: "true"
AWS_ENDPOINT: "https://hel1.your-objectstorage.com"
AWS_URL: "https://hel1.your-objectstorage.com/almoajil-prod"

PUSHER_APP_ID: ""
PUSHER_APP_KEY: ""
PUSHER_APP_SECRET: ""
PUSHER_HOST: ""
PUSHER_PORT: ""
PUSHER_SCHEME: ""
PUSHER_APP_CLUSTER: "mt1"
MIX_PUSHER_APP_KEY: "${PUSHER_APP_KEY}"
VITE_APP_NAME: "${APP_NAME}"
VITE_PUSHER_APP_KEY: "${PUSHER_APP_KEY}"
VITE_PUSHER_HOST: "${PUSHER_HOST}"
VITE_PUSHER_PORT: "${PUSHER_PORT}"
VITE_PUSHER_SCHEME: "${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER: "${PUSHER_APP_CLUSTER}"
VITE_HOST: "127.0.0.1:8000"

externalSecrets.yaml​

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: almoajil-prod-secrets
namespace: almoajil-prod
spec:
refreshInterval: "15m"
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: almoajil-prod-secrets
creationPolicy: Owner
data:
- secretKey: APP_KEY
remoteRef:
key: almoajil-prod/secrets
property: APP_KEY

- secretKey: DB_HOST
remoteRef:
key: almoajil-prod/secrets
property: DB_HOST

- secretKey: DB_PORT
remoteRef:
key: almoajil-prod/secrets
property: DB_PORT

- secretKey: DB_DATABASE
remoteRef:
key: almoajil-prod/secrets
property: DB_DATABASE

- secretKey: DB_USERNAME
remoteRef:
key: almoajil-prod/secrets
property: DB_USERNAME

- secretKey: DB_PASSWORD
remoteRef:
key: almoajil-prod/secrets
property: DB_PASSWORD

- secretKey: MAIL_HOST
remoteRef:
key: almoajil-prod/secrets
property: MAIL_HOST

- secretKey: MAIL_USERNAME
remoteRef:
key: almoajil-prod/secrets
property: MAIL_USERNAME

- secretKey: MAIL_PASSWORD
remoteRef:
key: almoajil-prod/secrets
property: MAIL_PASSWORD

- secretKey: MAIL_FROM_NAME
remoteRef:
key: almoajil-prod/secrets
property: MAIL_FROM_NAME

- secretKey: MAIL_FROM_ADDRESS
remoteRef:
key: almoajil-prod/secrets
property: MAIL_FROM_ADDRESS

- secretKey: MAIL_TO_ADDRESS
remoteRef:
key: almoajil-prod/secrets
property: MAIL_TO_ADDRESS

- secretKey: AWS_ACCESS_KEY_ID
remoteRef:
key: almoajil-prod/secrets
property: AWS_ACCESS_KEY_ID

- secretKey: AWS_SECRET_ACCESS_KEY
remoteRef:
key: almoajil-prod/secrets
property: AWS_SECRET_ACCESS_KEY

after that, either apply the files directly, or use argocd to deploy.