Summary
Shlink을 k3s 환경으로 설치하는 과정을 기록했습니다.
yaml
ConfigMap
컨테이너에 들어가는 환경 변수를 따로 ConfigMap의 형태로 만들어서 사용합니다.
apiVersion: v1
kind: ConfigMap
metadata:
name: shlink-config
namespace: apps
data:
TZ: "Asia/Seoul"
MULTI_SEGMENT_SLUGS_ENABLED: "true"
DEFAULT_DOMAIN: "link.junbeom.work" # 기본 도메인 설정
IS_HTTPS_ENABLED: "true"
DB_DRIVER: "postgres"
DB_HOST: "postgres-svc.core-infra.svc.cluster.local" # PostgreSQL 서비스 주소
REDIS_SERVERS: "tcp://shlink-redis-svc:6379"
SHELL_VERBOSITY: "3"
Tip
PostgreSQL이 같은 NameSpace에 있으면
DB_HOST: postgres-svc로 수정하면 됩니다.
Redis
Shlink는 Redis가 필요한 서비스이기 때문에 Redis가 설치가 포함됩니다.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: shlink-redis-pvc
namespace: apps
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-path
resources:
requests:
storage: 2Gi
---
apiVersion: v1
kind: Service
metadata:
name: shlink-redis-svc
namespace: apps
spec:
type: ClusterIP
selector:
app: shlink-redis
ports:
- name: redis
port: 6379
targetPort: 6379
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: shlink-redis
namespace: apps
spec:
replicas: 1
selector:
matchLabels:
app: shlink-redis
template:
metadata:
labels:
app: shlink-redis
spec:
containers:
- name: redis
image: redis:7-alpine
command: ["redis-server", "--save", "60", "1", "--loglevel", "warning"]
ports:
- containerPort: 6379
resources:
requests:
cpu: "100m"
memory: "50Mi"
limits:
cpu: "0.5"
memory: "256Mi"
volumeMounts:
- name: redis-data
mountPath: /data
volumes:
- name: redis-data
persistentVolumeClaim:
claimName: shlink-redis-pvcShlink Backend
Shlink의 백엔드 설정입니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: shlink-backend
namespace: apps
spec:
replicas: 1
selector:
matchLabels:
app: shlink-backend
template:
metadata:
labels:
app: shlink-backend
spec:
containers:
- name: backend
image: shlinkio/shlink:latest
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: shlink-config
env:
- name: DB_USER
valueFrom:
secretKeyRef:
name: shlink-secret
key: DB_USER
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: shlink-secret
key: DB_PASSWORD
- name: DB_NAME
valueFrom:
secretKeyRef:
name: shlink-secret
key: DB_NAME
- name: GEOLITE_LICENSE_KEY
valueFrom:
secretKeyRef:
name: shlink-secret
key: GEOLITE_LICENSE_KEY
livenessProbe:
httpGet:
path: /rest/health
port: 8080
initialDelaySeconds: 20
periodSeconds: 60
timeoutSeconds: 10
failureThreshold: 5
resources:
requests:
cpu: "100m"
memory: "500Mi"
limits:
cpu: "1.0"
memory: "1.5Gi"Shlink Web
Shlink의 웹 설정입니다.
apiVersion: v1
kind: Service
metadata:
name: shlink-web-svc
namespace: apps
spec:
type: ClusterIP
selector:
app: shlink-web
ports:
- name: http
port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: shlink-web
namespace: apps
spec:
replicas: 1
selector:
matchLabels:
app: shlink-web
template:
metadata:
labels:
app: shlink-web
spec:
containers:
- name: web
image: shlinkio/shlink-web-client:latest
ports:
- containerPort: 8080
env:
- name: TZ
value: "Asia/Seoul"
- name: SHLINK_SERVER_URL
value: "https://link.junbeom.work" # Backend 주소
- name: SHLINK_SERVER_API_KEY
valueFrom:
secretKeyRef:
name: shlink-secret
key: SHLINK_SERVER_API_KEY
livenessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 20
periodSeconds: 60
resources:
requests:
cpu: "50m"
memory: "20Mi"
limits:
cpu: "0.5"
memory: "256Mi"Backend Ingress
Shlink의 백엔드 담당 Ingress Controller 입니다. traefik을 사용해 SSL 인증서만 발급하여 모두가 볼 수 있습니다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shlink-backend-ingress
namespace: apps
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-cloudflare"
spec:
ingressClassName: traefik
tls:
- hosts:
- link.junbeom.work # 백엔드 도메인인
secretName: shlink-backend-tls-secret
rules:
- host: link.junbeom.work # 백엔드 도메인
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: shlink-backend-svc
port:
number: 8080Web Ingress
Shlink의 웹 담당 Ingress Controller 입니다. traefik을 이용한 SSL 발급과 내부망 제한 middleware를 적용하여 내부망에서만 접근 가능합니다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shlink-web-ingress
namespace: apps
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-cloudflare"
traefik.ingress.kubernetes.io/router.middlewares: "apps-internal-only@kubernetescrd"
spec:
ingressClassName: traefik
tls:
- hosts:
- shlink.junbeom.work # Web 도메인
secretName: shlink-web-tls-secret
rules:
- host: shlink.junbeom.work # Web 도메인
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: shlink-web-svc
port:
number: 8080Tip
모든 객체는
shlink.yaml에 포함됩니다.
Installation
Secret 생성
apiVersion: v1
kind: Secret
metadata:
name: shlink-secret
namespace: apps
type: Opaque
data:
DB_NAME: <DB_NAME>
DB_PASSWORD: <DB_PASSWORD>
DB_USER: <DB_USER>
GEOLITE_LICENSE_KEY: <GEOLITE_LICENSE_KEY>
SHLINK_SERVER_API_KEY: <SHLINK_SERVER_API_KEY>kubectl apply -f shlink-secret.yaml
Danger
secret.yaml은 중요한 정보가 들어있으므로 보통 생성하고 파일을 삭제합니다.
Tip
SHLINK_SERVER_API_KEY는 서비스를 먼저 배포한 후에 발급 받아야 합니다.
GEOLITE_LICENSE_KEY
Shlink는 주소별 접근 데이터 분석을 지원하기 때문에 위치 데이터와 DB 접근이 필요합니다.
- Maxmind 접근
- 계정 생성 및 로그인
My Account→MANAGE LICENSE KEYS→Generate new license key
배포
# shlink 배포
kubectl apply -f shlink.yaml
# API-KEY 생성
kubectl exec -it deployment/shlink-backend -n apps -- shlink api-key:generateSuccess
