Ubuntu 22.04 단일 서버 K3S Cluster 에서 Korifi 설치하기

리눅스/PaaS|2024. 1. 25. 14:20
반응형

K3S 는 경량 Kubernetes (클러스터 형태의 컨테이너 오케스트레이션) 구현체로, 리소스 사용이 적고 더 빠르게 구동됩니다.

때문에 Korifi 를 테스트 해보기 위한 사용자는 K3S 에서 구현해보고, 실제 서비스 구현 또는 대규모 분산 시스템을 원할 경우 다른 포스팅 (https://sysdocu.tistory.com/1904) 을 참고하여 구축하시기 바랍니다.

여기에서는 Korifi 0.7.1 / 0.10.0 / 0.11.0 세가지 방법으로 구분하여 작성하였으며, 꼭 필요한 명령어만 기술하고 설명을 최소화 하였습니다.

 

 

1. 사전 작업

 

Korifi 설치 및 사용에 필요한 명령어와 운영환경 K3S 를 우선 설치 합니다.

 

1) Kubectl

# curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
# install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

 

2) CF

# wget -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo apt-key add -
# echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list
# apt -y update

# apt -y install cf8-cli

3) Helm
# wget https://get.helm.sh/helm-v3.12.0-linux-amd64.tar.gz

# tar xvzf helm-v3.12.0-linux-amd64.tar.gz
# mv linux-amd64/helm /usr/local/bin/

 

4) K3S 설치

# curl -sfL https://get.k3s.io | sh -s - --disable traefik --write-kubeconfig-mode 644

# export KUBECONFIG="/etc/rancher/k3s/k3s.yaml"

 

앞으로 SSH 접속시마다 자동으로 환경이 로드 되도록 하면 편리합니다.

# echo 'export KUBECONFIG="/etc/rancher/k3s/k3s.yaml"' >> ~/.bashrc

 

 

2. 설치 진행

 

1) 환경변수 설정

# export ROOT_NAMESPACE="cf"

# export KORIFI_NAMESPACE="korifi"

# export ADMIN_USERNAME="cf-admin"

# export BASE_DOMAIN="az1.sysdocu.kr"

 

2) Cert Manager 설치

# kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.2/cert-manager.yaml

 

3) Kpack 설치

# kubectl apply -f https://github.com/buildpacks-community/kpack/releases/download/v0.13.2/release-0.13.2.yaml

 

4) 네임스페이스 생성
# cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
  name: $ROOT_NAMESPACE
  labels:
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/enforce: restricted
EOF

 

# cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
  name: $KORIFI_NAMESPACE
  labels:
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/enforce: restricted
EOF

 

5) Contour 설치

(Korifi 0.7.1 / 0.10.0 설치시)

# kubectl apply -f https://projectcontour.io/quickstart/contour.yaml

 

(Korifi 0.11.0 설치시)

정적 프로비저닝 방법으로 contour 를 설치합니다.
# export GATEWAY_CLASS_NAME="contour"
# kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/experimental-install.yaml
# kubectl apply -f - <<EOF
kind: GatewayClass
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
  name: $GATEWAY_CLASS_NAME
spec:
  controllerName: projectcontour.io/gateway-controller
EOF

# kubectl apply -f https://projectcontour.io/quickstart/contour-gateway.yaml

마지막 파일에 사용하지 않는 example 등의 이름으로 설치되는 요소가 있지만, 동작 여부만 확인할 예정이므로 그대로 설치하였습니다.

 

6) DNS 설정

본 매뉴얼은 서버 한대로 구성하는 것이므로 DNS 에서 아래 사용할 도메인의 IP 를 현재 서버 IP 로 셋팅해주어야 합니다.

- API 서버 도메인 : api.az1.sysdocu.kr - 115.68.248.245

- 애플리케이션이 사용할 도메인 : *.apps.az1.sysdocu.kr - 115.68.248.245

 

7) Secret 생성

여기에서는 실제 사용 가능한 Repository 정보를 입력해야 합니다.

# kubectl --namespace "$ROOT_NAMESPACE" create secret docker-registry image-registry-credentials \
    --docker-username="sysdocu" \
    --docker-password="12345678" \
    --docker-server="https://registry.az1.sysdocu.kr:5000"

 

8) Korifi 설치

여기에서도 실제 사용 가능한 Repository 정보를 입력해야 합니다.

(Korifi 0.7.1 설치시)

# helm install korifi https://github.com/cloudfoundry/korifi/releases/download/v0.7.1/korifi-0.7.1.tgz \
    --namespace="$KORIFI_NAMESPACE" \
    --set=global.generateIngressCertificates=true \
    --set=global.rootNamespace="$ROOT_NAMESPACE" \
    --set=global.containerRegistrySecret="image-registry-credentials" \
    --set=adminUserName="$ADMIN_USERNAME" \
    --set=api.apiServer.url="api.$BASE_DOMAIN" \
    --set=global.defaultAppDomainName="apps.$BASE_DOMAIN" \
    --set=global.containerRepositoryPrefix="registry.az1.sysdocu.kr:5000/" \
    --set=kpackImageBuilder.builderRepository="registry.az1.sysdocu.kr:5000/kpack-builder" \
    --wait

 

(Korifi 0.10.0 설치시)

# helm install korifi https://github.com/cloudfoundry/korifi/releases/download/v0.10.0/korifi-0.10.0.tgz \
    --namespace="$KORIFI_NAMESPACE" \
    --set=generateIngressCertificates=true \
    --set=rootNamespace="$ROOT_NAMESPACE" \
    --set=containerRegistrySecret="image-registry-credentials" \
    --set=adminUserName="$ADMIN_USERNAME" \
    --set=api.apiServer.url="api.$BASE_DOMAIN" \
    --set=defaultAppDomainName="apps.$BASE_DOMAIN" \
    --set=containerRepositoryPrefix="registry.az1.sysdocu.kr:5000/" \
    --set=kpackImageBuilder.builderRepository="registry.az1.sysdocu.kr:5000/kpack-builder" \
    --wait

 

(Korifi 0.11.0 설치시)

# helm install korifi https://github.com/cloudfoundry/korifi/releases/download/v0.11.0/korifi-0.11.0.tgz \
    --namespace="$KORIFI_NAMESPACE" \
    --set=adminUserName="$ADMIN_USERNAME" \
    --set=defaultAppDomainName="apps.$BASE_DOMAIN" \
    --set=generateIngressCertificates="true" \
    --set=api.apiServer.url="api.$BASE_DOMAIN" \
    --set=containerRepositoryPrefix="registry.az1.sysdocu.kr:5000/" \
    --set=kpackImageBuilder.clusterStackBuildImage="paketobuildpacks/build-jammy-full" \
    --set=kpackImageBuilder.clusterStackRunImage="paketobuildpacks/run-jammy-full" \
    --set=kpackImageBuilder.builderRepository="registry.az1.sysdocu.kr:5000/kpack-builder" \
    --set=networking.gatewayClass="$GATEWAY_CLASS_NAME" \
    --wait

 

9) CF 관리자 계정 생성

CF 관리자 계정 cf-admin 을 추가합니다.

생성 명령 절차가 길어 명령어 앞에 프롬프트를 제거하였습니다. 아래 명령을 전체 복사하여 실행하면 됩니다.

cf-admin 이 아닌 계정명으로 변경하고 싶을 경우 아래 내용에서 cf-admin 문자열을 다른 계정 ID 로 치환하여 실행하면 됩니다.

openssl genrsa -out cf-admin.key 2048
openssl req -new -key cf-admin.key -out cf-admin.csr -subj "/CN=cf-admin"
tmp=`cat cf-admin.csr | base64 | tr -d "\n"`
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: cf-admin
spec:
  request: $tmp
  signerName: kubernetes.io/kube-apiserver-client
  #expirationSeconds: 604800 # 1주일 (옵션 미사용시 : 1년 유효)
  usages:
    - client auth
EOF
kubectl certificate approve cf-admin
kubectl get csr cf-admin -o jsonpath='{.status.certificate}'| base64 -d > cf-admin.crt
kubectl create role developer --verb=create --verb=get --verb=list --verb=update --verb=delete --resource=pods
kubectl create rolebinding developer-binding-cf-admin --role=developer --user=cf-admin
kubectl config set-credentials cf-admin --client-key=cf-admin.key --client-certificate=cf-admin.crt --embed-certs=true
kubectl config set-context cf-admin --cluster=kubernetes --user=cf-admin

 

 

3. 애플리케이션 배포

 

1) Cloud Foundry API 로그인

# cf api https://api.$BASE_DOMAIN --skip-ssl-validation

# cf auth cf-admin

 

2) 조직 및 공간 생성

# cf create-org org1

# cf create-space -o org1 space1
# cf target -o org1 -s space1

3) 애플리케이션 배포

준비된 소스 코드가 없다면, 공개된 샘플 소스 코드를 다운로드하고 배포해 봅니다.

# git clone https://github.com/sylvainkalache/sample-web-apps

# cd sample-web-apps/java

# cf push java1

 

배포할때 특이점은, Korifi 0.7.1 의 경우 동작 프로세스가 화면에 잘 출력되는 반면, 0.10.0 부터는 처리과정 출력 없이 마지막에 인스턴스를 시작하는 단계에서부터 출력되므로, 중간에 멈춘것 같은 느낌이 들지만 인내를 가지고 기다려 보시기 바랍니다. timeout 시간이 15분으로, 그 전까지 배포되지 않을 경우 에러가 출력됩니다.

 

4) 애플리케이션 확인

배포된 애플리케이션에 접근합니다.

# curl --insecure https://java1.apps.az1.sysdocu.kr 

Hello, World!
Java Version: 17.0.10

 

반응형

댓글()

GitLab CLI Tool (GLab) 설치 및 사용하기

리눅스/PaaS|2024. 1. 23. 14:15
보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

Ubuntu 22.04 에서 zip, rar 등 분할 압축 파일 해제하기 (압축 풀기)

리눅스/OS 일반|2024. 1. 22. 16:54
반응형

압축 파일이 분할 저장된 경우, 종류에 상관없이 모두 풀어버리는 유틸리티가 있습니다.

여기에서는 zip 파일을 예시로 들었지만 다른 압축 형태도 풀리므로 아래와 같이 사용해 보세요.

 

파일 리스트

- test.zip

- test.z01

- test.z02

 

패키지 설치

# apt -y install p7zip-full

 

압축 해제

# 7za x test.zip

반응형

댓글()

Ubuntu 22.04 에서 GitLab CE (Community Edition) 설치 및 사용하기

리눅스/PaaS|2024. 1. 19. 11:21
보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

Kind Cluster + Korifi 설치 스크립트로 환경 구성시 CF 로 배포되는 앱 CPU Limit 제한 설정하기

리눅스/PaaS|2024. 1. 16. 09:07
보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

[Kubernetes] metrics-server 설치하기 (error: Metrics API not available 조치)

반응형

metrics-server 는 Kubernetes 클러스터 내에서 노드 및 Pod 의 리소스 사용량에 대한 메트릭 데이터를 수집하고 제공하는 서버입니다. 이러한 메트릭 데이터는 Kubernetes API 서버를 통해 조회할 수 있어, 사용자나 다른 Kubernetes 구성 요소들이 클러스터의 성능 및 리소스 사용에 대한 정보를 얻을 수 있습니다.

metrics-server 가 제공하는 주요 메트릭은 다음과 같습니다:
- CPU 사용량 (CPU Usage) : 클러스터 내의 각 노드 및 Pod 가 사용하는 CPU 의 양을 측정합니다.
- 메모리 사용량 (Memory Usage) : 클러스터 내의 각 노드 및 Pod 가 사용하는 메모리의 양을 측정합니다.
- 네트워크 입출력 (Network I/O) : 클러스터 내의 각 노드 및 Pod 가 수행하는 네트워크 입출력을 측정합니다.
- 파일 시스템 사용량 (Filesystem Usage) : 클러스터 내의 각 노드 및 Pod 가 사용하는 파일 시스템의 용량과 사용량을 측정합니다.

이러한 메트릭 데이터는 Kubernetes 의 Horizontal Pod Autoscaling (HPA) 및 기타 리소스 관리 및 모니터링 도구에서 사용됩니다. metrics-server 는 일반적으로 클러스터 내에서 자동으로 배포되며, Kubernetes 버전 1.8 이상에서는 기본적으로 활성화됩니다.

사용자는 kubectl top 명령을 통해 metrics-server 에서 수집된 메트릭 데이터를 조회할 수 있습니다. 예를 들어, kubectl top pods, kubectl top nodes 등을 사용하여 Pod 및 노드의 리소스 사용량을 확인할 수 있습니다.

 

 

1. Metrics-server 설치

 

설치는 한번의 명령으로 끝이 납니다.

아래 URL 은 공식 배포 URL 로써 항상 최신버전의 metrics-server 가 설치 됩니다.

# kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
serviceaccount/metrics-server created
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
clusterrole.rbac.authorization.k8s.io/system:metrics-server created
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created
service/metrics-server created
deployment.apps/metrics-server created
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created

 

명령이 잘 실행되는지 확인합니다.

아래는 nodes 의 자원 사용률 확인 명령입니다.

# kubectl top nodes
error: Metrics API not available

 

이와 동일한 에러가 출력된 경우, metrics-server Pod 가 잘 생성되었는지 확인합니다.

# kubectl get pod -A |grep metrics
kube-system                                     metrics-server-5d875656f5-vmv66                                 0/1     Running     0          10s

 

설치가 되었으나 Running 중인 Pod 는 0개로 확인 됩니다.

Pod 의 상세 정보에서는 HTTP status code 500 에러가 확인되었습니다.

# kubectl describe pod metrics-server-5d875656f5-vmv66 -n kube-system

...

(생략)

...

Events:
  Type     Reason     Age               From               Message
  ----     ------     ----              ----               -------
  Normal   Scheduled  52s               default-scheduler  Successfully assigned kube-system/metrics-server-5d875656f5-vmv66 to kind-control-plane
  Normal   Pulled     51s               kubelet            Container image "registry.k8s.io/metrics-server/metrics-server:v0.6.4" already present on machine
  Normal   Created    51s               kubelet            Created container metrics-server
  Normal   Started    51s               kubelet            Started container metrics-server
  Warning  Unhealthy  1s (x4 over 31s)  kubelet            Readiness probe failed: HTTP probe failed with statuscode: 500

 

문제 해결을 위해 Deployment 를 수정합니다.

# kubectl edit deployment metrics-server -n kube-system

출력된 내용중에 metric-resolution 문자열을 검색해서 그 다음에 옵션을 하나 더 추가해 주어야 하는데, 문자열을 검색하면 두 군데 나옵니다. 그중에서 아래와 같이 옵션이 행으로 구분된 곳에 --kubelet-insecure-tls 옵션을 추가해 줍니다.

kubelet-insecure-tls 옵션은 공식적으로 발급받은 인증서인지 확인하지 않고 접근하겠다는 의미입니다.

...

(생략)

...

    spec:
      containers:
      - args:
        - --cert-dir=/tmp
        - --secure-port=4443
        - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
        - --kubelet-use-node-status-port
        - --metric-resolution=15s
        - --kubelet-insecure-tls
        image: registry.k8s.io/metrics-server/metrics-server:v0.6.4

...

(생략)

...

 

저장 후 시간이 조금 지나야 적용됩니다.

적용이 되면 아래와 같이 자원 사용량 확인이 가능합니다.

# kubectl top nodes
NAME                 CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
kind-control-plane   294m         3%     2753Mi          17%  

 

# kubectl top pods
NAME                                                    CPU(cores)   MEMORY(bytes)   
b07a7888-df03-451f-8475-13c6d9bac48d-cf--cb3e18e9fd-0   1m           4Mi             
nginx-665cb6f744-wf5g5                                  0m           6Mi      

 

반응형

댓글()

[Kubernetes] 네임스페이스의 메모리 및 CPU 할당량 구성

반응형

네임스페이스에 일정 용량을 적용하여 그 안의 Pod 가 제한된 용량 안에서만 자원을 나누어 사용할 수 있도록 합니다.

본 매뉴얼은 아래 공식 문서를 참고하여 작성하였습니다.

https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/quota-memory-cpu-namespace/

 

 

1. 네임스페이스 생성

 

테스트를 위한 네임스페이스를 생성합니다.

# kubectl create namespace sysdocu-ns

 

 

2. 할당량 생성 및 적용

 

네임스페이스에 적용할 할당량을 설정합니다.

# vi rq.yaml

apiVersion: v1
kind: ResourceQuota
metadata:
  name: mem-cpu-limits
spec:
  hard:
    requests.cpu: "1"
    requests.memory: 1Gi
    limits.cpu: "2"
    limits.memory: 2Gi

 

작성한 할당량을 먼저 생성한 네임스페이스에 적용합니다.

# kubectl apply -f rq.yaml -n sysdocu-ns
resourcequota/mem-cpu-limits created

 

설정한 리소스 할당량과 사용량에 대한 정보를 볼 수 있습니다.

# kubectl get resourcequota mem-cpu-limits -n sysdocu-ns --output=yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"ResourceQuota","metadata":{"annotations":{},"name":"mem-cpu-limits","namespace":"sysdocu-ns"},"spec":{"hard":{"limits.cpu":"2","limits.memory":"2Gi","requests.cpu":"1","requests.memory":"1Gi"}}}
  creationTimestamp: "2024-01-11T00:29:34Z"
  name: mem-cpu-limits
  namespace: sysdocu-ns
  resourceVersion: "12801859"
  uid: 98127c56-33bc-4ccc-a55c-1152b7f04128
spec:
  hard:
    limits.cpu: "2"
    limits.memory: 2Gi
    requests.cpu: "1"
    requests.memory: 1Gi
status:
  hard:
    limits.cpu: "2"
    limits.memory: 2Gi
    requests.cpu: "1"
    requests.memory: 1Gi
  used:
    limits.cpu: "0"
    limits.memory: "0"
    requests.cpu: "0"
    requests.memory: "0"

 

위 예시의 리소스 할당량 (ResourceQuota : mem-cpu-limits) 이 설정된 네임스페이스에 다음과 같은 제약 사항이 있습니다.
- 네임스페이스의 모든 Pod 에 대해 각 컨테이너에는 메모리 요청, 메모리 제한, CPU 요청 및 CPU 제한이 있어야 합니다.
- 해당 네임스페이스에 있는 모든 Pod 에 대한 메모리 요청 합계는 1 GiB 를 초과해서는 안 됩니다.
- 해당 네임스페이스에 있는 모든 Pod 의 메모리 제한 합계는 2 GiB 를 초과해서는 안 됩니다.
- 해당 네임스페이스에 있는 모든 포드에 대한 CPU 요청 합계는 1 CPU 를 초과해서는 안 됩니다.
- 해당 네임스페이스에 있는 모든 포드의 CPU 제한 합계는 2 CPU 를 초과해서는 안 됩니다.

 

 

3. 첫번째 Pod 생성

 

테스트를 위해 간단한 Pod 를 생성합니다.

# vi pod1.yaml

apiVersion: v1
kind: Pod
metadata:
  name: demo-pod1
spec:
  containers:
  - name: demo-pod1
    image: nginx
    resources:
      limits:
        memory: "800Mi"
        cpu: "800m"
      requests:
        memory: "600Mi"
        cpu: "400m"

 

# kubectl apply -f pod1.yaml -n sysdocu-ns
pod/demo-pod1 created

 

Pod 가 정상 실행되고 있는지 확인합니다.

# kubectl get pod demo-pod1 -n sysdocu-ns
NAME        READY   STATUS    RESTARTS   AGE
demo-pod1   1/1     Running   0          80s

 

설정한 리소스 할당량과 사용량에 대한 정보를 다시 확인합니다.

아래와 같이 사용량이 변경된 것을 확인할 수 있습니다.

# kubectl get resourcequota mem-cpu-limits -n sysdocu-ns --output=yaml

apiVersion: v1
kind: ResourceQuota
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"ResourceQuota","metadata":{"annotations":{},"name":"mem-cpu-limits","namespace":"sysdocu-ns"},"spec":{"hard":{"limits.cpu":"2","limits.memory":"2Gi","requests.cpu":"1","requests.memory":"1Gi"}}}
  creationTimestamp: "2024-01-11T00:29:34Z"
  name: mem-cpu-limits
  namespace: sysdocu-ns
  resourceVersion: "12805135"
  uid: 98127c56-33bc-4ccc-a55c-1152b7f04128
spec:
  hard:
    limits.cpu: "2"
    limits.memory: 2Gi
    requests.cpu: "1"
    requests.memory: 1Gi
status:
  hard:
    limits.cpu: "2"
    limits.memory: 2Gi
    requests.cpu: "1"
    requests.memory: 1Gi
  used:
    limits.cpu: 800m
    limits.memory: 800Mi
    requests.cpu: 400m
    requests.memory: 600Mi

 

jq 명령어 사용이 가능한 시스템에서는 아래와 같이 필요한 항목만 출력시킬 수 있습니다.

# kubectl get resourcequota mem-cpu-limits -n sysdocu-ns -o jsonpath='{ .status.used }' | jq .
{
  "limits.cpu": "800m",
  "limits.memory": "800Mi",
  "requests.cpu": "400m",
  "requests.memory": "600Mi"
}

 

 

4. 두번째 Pod 생성

 

테스트를 위해 두번째 Pod 를 생성합니다.

# vi pod2.yaml

apiVersion: v1
kind: Pod
metadata:
  name: demo-pod2
spec:
  containers:
  - name: demo-pod2
    image: redis
    resources:
      limits:
        memory: "1Gi"
        cpu: "800m"
      requests:
        memory: "700Mi"
        cpu: "400m"

 

# kubectl apply -f pod2.yaml -n sysdocu-ns
Error from server (Forbidden): error when creating "pod2.yaml": pods "demo-pod2" is forbidden: exceeded quota: mem-cpu-limits, requested: requests.memory=700Mi, used: requests.memory=600Mi, limited: requests.memory=1Gi

 

네임스페이스 내에서 사용 가능한 요청 메모리가 1Gi 인데, Pod1 의 메모리 600MiB 에 Pod2 의 메모리 700MiB 를 추가하려니까 에러가 발생했습니다.

600MiB + 700MiB > 1 GiB.

 

이렇게 ResourceQuota 을 이용해 네임스페이스에 리소스 할당량을 사용하여 제한하는 방법을 알아보았습니다.

 

반응형

댓글()

ab 명령을 이용한 웹서버 로딩 속도 테스트

리눅스/APACHE|2024. 1. 9. 13:57
보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.