쿠버네티스를 이용한 웹호스팅 서비스 구현 1
이번장에서는 여러명의 사용자를 생성하고 이 사용자들이 각각의 home directory(document root)를 사용하는 일반적인 웹호스팅 같은 서비스를 구현해 보겠습니다.
-
- mariadb
-
- ssh/sftp, npm, php cli
-
- nginx / php-fpm
-
- Putty, Filezilla, HeidiSQL 로 각각의 서비스 접속하기
-
- laravel (php framework)
관리자는 사용자 계정을 생성가능하게 하고, nginx 등을 도메인에 맞게 수정해야 겠죠?
먼저 웹호스팅할 스토리지를 만들고 php-fpm 으로 돌아가는 nginx를 만들겠습니다. 물론 mariadb도 설치해야 겠죠.
그리고 생성된 유저가 ssh 를 통해 접속 하여 laravel 을 설치 및 실제 db와 연결하는 단계들을 하겠습니다.
물론 관리자가 하는 것은 유저가 ssh에 접속 가능하게 까지만 하고 그다음 laravel 설치는 user의 입장에서 처리하도록 햐겠습니다.
이문서는 이전에 설명드린 php-fpm, mariadb, nginx 그리고 laravel 설치하기 와 관련이 있으며 좀더 자세히 설명드리는 예제입니다.
Image 및 yaml 만들기
1. Mariadb
마리아 db 용으로 PersistentVolume 및 PersistentVolumeClaim 을 생성하고 mariadb는 StatefulSet 으로 제작하겠습니다.
1.1 mariadb-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: mariadb-pv
spec:
capacity:
storage: 1Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
hostPath:
path: /data/mariadb
1.2 mariadb-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mariadb-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
1.3 mariadb-statefulset.yaml
---
apiVersion: v1
kind: Service
metadata:
name: mariadb-service
spec:
selector:
app: mariadb
ports:
- port: 3306
targetPort: 3306
nodePort: 30006 #Choose a port on your node (e.g., 30006)
type: NodePort
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mariadb-statefulset
spec:
serviceName: mariadb
replicas: 1
selector:
matchLabels:
app: mariadb
template:
metadata:
labels:
app: mariadb
spec:
containers:
- name: mariadb
image: mariadb:latest
env:
- name: MYSQL_ROOT_PASSWORD
value: your_password_here
ports:
- containerPort: 3306
volumeMounts:
- mountPath: /var/lib/mysql
name: mariadb-storage
volumeClaimTemplates:
- metadata:
name: mariadb-storage
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
1.4 생성하기
kubectl apply -f mariadb-pv.yaml
kubectl apply -f mariadb-pvc.yaml
kubectl apply -f mariadb-statefulset.yaml
1.5 콘솔 접근 및 사용자 계정 생성
kubectl exec -it <pod_name> -- /bin/bash
$ mariadb -uroot -p[your_password_here]
2. SSH
여기서는 ssh 뿐만 아니라 laravel 에서는 composer, php-cli, npm 등을 사용하므로 이들을 함께 운영할 수 있는 Docker Image를 제작하도록 하겠습니다.
2.1 create-users.sh
SSH용 Docker 이미지를 만들때 초기 유저들을 세팅한다.
- creat-users.sh
#!/bin/bash
# www-data 그룹이 없으면 생성 (보통 nginx 이미지에는 존재함)
getent group www-data >/dev/null || groupadd www-data
# 유저 목록 정의: "user:password" 형식
# USERS=("user1:password1" "pondol:password2") // 수동으로 기존 사용자를 추가했으면 이곳에서 입력해 두는 것이 시스템 유지에 좋다.
USERS=()
for entry in "${USERS[@]}"; do
USERNAME=$(echo "$entry" | cut -d: -f1)
PASSWORD=$(echo "$entry" | cut -d: -f2)
if id "$USERNAME" &>/dev/null; then
echo "User $USERNAME already exists"
else
echo "Creating user $USERNAME..."
# useradd -m -s /bin/bash "$USERNAME"
useradd -m -s /bin/bash -G www-data "$USERNAME"
echo "$USERNAME:$PASSWORD" | chpasswd
mkdir -p "/home/$USERNAME"
chown "$USERNAME:$USERNAME" "/home/$USERNAME"
chmod 755 "/home/$USERNAME"
fi
done
echo "All users created. Starting SSH..."
2.2 ssh 콘솔에서 사용할 이미지 제작
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive # 질문없이 기본 값으로 입력
# 시스템 패키지 업데이트 및 기본 도구 설치
RUN apt update && apt install -y \
curl \
wget \
gnupg2 \
lsb-release \
ca-certificates \
software-properties-common \
vim \
sudo \
unzip \
git \
passwd \
openssh-server \
php-cli php-mbstring php-xml php-curl php-zip php-bcmath php-tokenizer php-mysql php-common \
php-gd php-soap php-intl php-readline
# Node.js 18 설치 (Ubuntu 공식 방법)
RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \
apt install -y nodejs
# # Get NodeJS
# COPY --from=node:20-slim /usr/local/bin /usr/local/bin
# # Get npm
# COPY --from=node:20-slim /usr/local/lib/node_modules /usr/local/lib/node_modules
# Composer 설치
RUN curl -sS https://getcomposer.org/installer | php && \
mv composer.phar /usr/local/bin/composer
# # Get Composer
# COPY --from=composer:2.7 /usr/bin/composer /usr/bin/composer
# SSH 설정
RUN mkdir /var/run/sshd
RUN echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config
RUN echo 'PasswordAuthentication yes' >> /etc/ssh/sshd_config
# 위에서 만든 create-users.sh 를 이용하여 기존 사용자를 자동 등록
## 기본 사용자 추가 스크립트 복사
COPY create-users.sh /usr/local/bin/create-users.sh
RUN chmod +x /usr/local/bin/create-users.sh
## SSH 시작 시 사용자 자동 추가
CMD ["/bin/bash", "-c", "/usr/local/bin/create-users.sh && /usr/sbin/sshd -D"]
2.3 Build 및 Docker Hub로 업로드
docker build -t [your-dockerhub-username]/[이미지명]:[태그] -f [Dockerfile] .
docker build -t pondol/ssh-web-users:latest -f ssh-web-users.Dockerfile .
docker push pondol/ssh-web-users:latest
3. Nginx + PHP-FPM 구축하기
위에서 만든 ssh 및 이용하여 Nginx + Php-Fpm을 구축하겠습니다.
3.1 Nginx 용 Config
3.1.1 nginx-main-config.yaml
여기서 중요한 것은 user를 www-data로 변경하는 것입니다.
ssh 와 nginx의 group user 를 통일함으로서 퍼미션 문제를 처리하기 위해서 입니다.
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-main-config
data:
nginx.conf: |
user www-data;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
3.1.2 nginx-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
default.conf: | # 키명 = 파일명, |은 밸류가 멀티라인이라는 뜻
server {
listen 80;
listen [::]:80;
server_name localhost;
access_log /var/log/nginx/host.access.log;
error_log /var/log/nginx/host.error.log;
# root /home/pondol/example-app/public;
root /usr/share/nginx/html;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param REQUEST_METHOD $request_method;
# fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
kubectl apply -f .\nginx-main-config.yaml
kubectl apply -f .\nginx-config.yaml
3.2 PHP-FPM
nginx 는 docker hub에 있는 nginx:1.27.5 Image를 사용할 예정이나
PHP-FPM의 경우 프로젝트들에 필요한 모듈들을 좀더 추가하여 Image를 만들어 사용하겠습니다.
- php-8-2-fpm.Dockerfile
FROM php:8.2-fpm
# 필요한 시스템 패키지 설치
RUN apt-get update && apt-get install -y \
default-mysql-client \
libpng-dev \
libjpeg-dev \
libonig-dev \
libxml2-dev \
zip \
unzip \
vim \
&& docker-php-ext-install mysqli pdo pdo_mysql
이 파일은 docker 에 올리지 않고 local에서 생성하여 바로 사용하겠습니다.
docker build -t php-8-2-fpm:latest -f php-8-2-fpm.Dockerfile .
Development.yaml 만들기
이제 모든 것이 다 준비되었습니다.
- deployment.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: shared-home-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
name: sftp-ssh-service
spec:
selector:
app: nginx-phpfpm
type: NodePort
ports:
- name: ssh
protocol: TCP
port: 22
targetPort: 22
nodePort: 30222
- name: http
protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-phpfpm-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx-phpfpm
template:
metadata:
labels:
app: nginx-phpfpm
spec:
securityContext:
fsGroup: 1000
runAsUser: 0
volumes:
- name: shared-home
persistentVolumeClaim:
claimName: shared-home-pvc
- name: nginx-main-config
configMap:
name: nginx-main-config
- name: nginx-config-volume
configMap:
name: nginx-config
containers:
- name: nginx
image: nginx:1.27.5
ports:
- containerPort: 80
name: http
volumeMounts:
- name: shared-home
mountPath: /home
- name: nginx-main-config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
- name: nginx-config-volume
mountPath: /etc/nginx/conf.d
- name: ssh
image: pondol/ssh-web-users:latest
ports:
- containerPort: 22
name: ssh
volumeMounts:
- name: shared-home
mountPath: /home
- name: phpfpm82
image: php-8-2-fpm:latest
imagePullPolicy: Never
volumeMounts:
- name: shared-home
mountPath: /home
kubectl apply -f .\deployment.yaml
계정 생성
모든 세팅이 마무리되면 웹 호스팅 서비스를 제공할 모든 것이 만들어 졌다.
여기서 우리가 할 일은 관리자 권한(root)으로 1. ssh(sftp) 계정만들기, 2. mariadb 데이타베이스 만들기, 3. nginx와 연동 을 한 후
만들어진 계정으로 접속하여 1. laravel 프로젝트 만들기, 2, db 연동 등을 다루어 보겠습니다.
1. 사용자 계정생성
kubectl exec -it nginx-phpfpm-deployment-74bbb7d68b-z9lzj -c ssh -- /bin/bash
$ adduser -home /home/pondol pondol // 커멘드라인에서 pondol 이라는 계정을 만들고 패스워드를 입력한다.
$ sudo chgrp www-data /home/pondol
- putty에서 테스트 하기
아래 정보를 입력하여 putty 나 filezilla 를 이용하여 접속하여 보자
ip : 127.0.0.1
port : 30222
username : pondol
password : ...
2. 사용자 데이타 베이스 만들기
위에서 만든 mariadb에 접속하여 사용자 db를 만들어 보자
kubectl exec -it mariadb-statefulset-0 -- /bin/bash
$ mariadb -uroot -p[your_password_here]
MariaDB [(none)]> create database db_pondol;
grant all privileges on db_pondol.* to pondol@[클라이언트에서 접속할 IP] identified by '[db password here]'; // heidiSQL 같이 클라이언트를 이용하여 접속할 ip
grant all privileges on db_pondol.* to pondol@[container 에서 접속할 IP] identified by '[db password here]'; // kubectl get pod -o wide 를 사용하여 nginx-phpfpm-deployment의 IP 사용
위와 같이 두군데에서 접속할 ip를 각각 세팅해 둔다.
- HeidiSql 접속 정보
ip : 127.0.0.1
user : pondol
password: ....
port : 30006
3. nginx 세팅
마지막으로 nginx 만 설치하면 사용자가 서비스를 할 정보는 다 된다.
여기서 laravel을 설치할 예정인데 document directory는 /home/pondon/example-app/public 을 사용할 예정이다.
configMap으로 설정되었으므로 vi editor로는 수정이 불가능하다. 따라서 위의 nginx-config.yaml 을 다시 수정하여야 한다.
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
default.conf: | # 키명 = 파일명, |은 밸류가 멀티라인이라는 뜻
server {
listen 80;
listen [::]:80;
server_name localhost;
access_log /var/log/nginx/host.access.log;
error_log /var/log/nginx/host.error.log;
root /home/pondol/example-app/public; # <-- /usr/share/nginx/html;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param REQUEST_METHOD $request_method;
# fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
kubectl apply -f .\nginx-config.yaml
// 가끔 안먹는 경우가 있는데 service nginx reload 를 사용하시기를
4.laravel 설치
4.1 laravel 설치
위에서 만든 pondol 이라는 사용자 계정으로 putty를 이용해 접근하겠습니다.
$ cd /home/pondol
$ composer create-project "laravel/laravel:^10.0" example-app // composer 를 이용하여 laravel 설치
$ cd ./example-app
$ vi .env // .env 에서 아래와 같이 db 정보만 변경
4.2 .env 에서 mysql 정보 변경
DB_CONNECTION=mysql
DB_HOST=mariadb-service
DB_PORT=3306 # service의 내부 포터를 사용
DB_DATABASE=db_pondol
DB_USERNAME=pondol
DB_PASSWORD=...
4.3 퍼미션 변경 (root에서)
$ sudo chgrp - R www-data /home/pondol/example-app # 하위 디렉토리에 모두 www-data 그룹을 추가
4.3 사용자 계정에서 laravel 설치 마무리 하기
$ example-app$ php artisan migrate
db_pondol 보면 기본 table들이 생성 되어 있으면 OK.
이로서 우리는 웹호스팅 서비스를 만들었고 laravel 을 띄우는 작업까지 완료 하였습니다.