updated_at: 2025-06-28 22:52

쿠버네티스를 이용한 웹호스팅 서비스 구현 1

이번장에서는 여러명의 사용자를 생성하고 이 사용자들이 각각의 home directory(document root)를 사용하는 일반적인 웹호스팅 같은 서비스를 구현해 보겠습니다.

    1. mariadb
    1. ssh/sftp, npm, php cli
    1. nginx / php-fpm
    1. Putty, Filezilla, HeidiSQL 로 각각의 서비스 접속하기
    1. 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 을 띄우는 작업까지 완료 하였습니다.

평점을 남겨주세요
평점 : 2.5
총 투표수 : 1

질문 및 답글