쿠버네티스 관련된 기술들이 워낙 많다보니 뭘 어디서부터 손대야할지 모를때도 있고 하다보면 어디에 서 있는지도 모를때가 있다. 더 나가 쿠버네티스를 시작하려고할때에 이게 어디에 있는건지를 알고 싶을때가 종종 있는데, 웹 서핑을 하다가 주운걸 기록해본다. 딱봐도 채용공고에 내용인데, 굵직하게 정리가 되어서 긁어왔다. 여기서 한가지 추가해야 한다면 IaC 부분인데, 요새는 쿠버네티스에 뭔가를 설치할때는 다음과 같은 걸 많이 사용한다. ArgoCD 도 있지만 이것은 사실 애플리케이션 배포에 쓰인다고 보면 된다. 요새 하도 공부를 하지 않아서 잃어버리는 기억도 많고 이제는 쓰지 않는 기술들도 많은데, 슬슬 다시 공부를해야 […]
컨테이너에서 Java 힙 덤프 뜨기
Kubernetes 에서 Java 애플리케이션을 운영할때에, Java 힙 덤프를 떠야하는 경우가 있다. 하지만 다음과 같이 덤프를 떠지지 않는다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$ kubectl exec -it employee-consumer-68cfc9864-kgx4w -- sh / # ps aux PID USER TIME COMMAND 1 root 3:01 java -XX:+UseG1GC -XX:+UseStringDeduplication -XX:MetaspaceSize=128M -XX:MaxMetaspaceSize=128M -Djava.security.egd=file:/dev/./urandom -jar /app/employee-consumer.jar --spring.active.profile=${SPRING_PROFILES_ACTIVE} 57 root 0:00 sh 63 root 0:00 ps aux / # jcmd 1 VM.flags 1: com.sun.tools.attach.AttachNotSupportedException: Unable to get pid of LinuxThreads manager thread at sun.tools.attach.LinuxVirtualMachine.<init>(LinuxVirtualMachine.java:86) at sun.tools.attach.LinuxAttachProvider.attachVirtualMachine(LinuxAttachProvider.java:63) at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:208) at sun.tools.jcmd.JCmd.executeCommandForPid(JCmd.java:147) at sun.tools.jcmd.JCmd.main(JCmd.java:131) / # </init> |
“Unable to get pid of LinuxThread manager thread” 오류가 발생한다. 이 오류가 나오는 이유는 Java 애플리케이션의 Pid 값이 1이기 때문이다. 이를 해결하는 방법을 소개한다. Container 이미지에 tini 설치, 배포 먼저 Openjdk 의 컨테이너 이미지에 tini 프로그램을 설치해야 한다. 이 tini 라는 프로그램은 인자값을 받은 프로그램을 실행 시켜 준다. 이렇게 하면 tini 는 Pid 1을 가지지만 tini 가 실행시킨 프로그램은 1보다 큰 Pid […]
Kubernetes API 서버 인증서에 도메인 추가하기
Kubernetes API 서버는 http 를 통해서 쿠버네티스에 대한 연산을 제공해 준다. kubectl 명령어로 실행되는 것들은 모두 API 서버를 거쳐서 이루어진다. 하지만 API 서버는 인증서를 기반으로 통신이 이루어지는데, 이 인증서에 기재된 도메인이나 IP가 아니면 통신이 이루어지지 않는다.
1 |
kubectl unable to connect to server: x509: certificate signed by unknown authority |
API 서버의 인증서는 SAN 인증서여야 한다. 도메인 리스트를 가지고 있는 SAN 인증서. 현재 API 서버의 인증서 상태는 다음과 같다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ openssl x509 -text -in /etc/kubernetes/pki/apiserver.crt -noout X509v3 extensions: X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: TLS Web Server Authentication X509v3 Basic Constraints: critical CA:FALSE X509v3 Authority Key Identifier: keyid:98:B6:19:7B:C4:FF:03:49:74:7D:F3:F1:7E:31:67:91:D9:2E:B5:EA X509v3 Subject Alternative Name: DNS:haproxy2.systemv.local, DNS:kmaster, DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, DNS:ol85.systemv.local, DNS:rhel8.systemv.local, IP Address:10.96.0.1, IP Address:192.168.96.23, IP Address:192.168.96.30, IP Address:192.168.96.7 Signature Algorithm: sha256WithRSAEncryption |
위 apiserver.crt 파일 상태를 보면 SAN 에 이미 도메인과 IP 들이 들어가 있다. 내용을 보면 haproxy2.systemv.local 도메인, 192.168.96.7 IP 가 들어가 있는데 이 […]
Kubernetes 의 Role Based Access Control(RBAC)
쿠버네티스는 RBAC 기반으로 허가권(Permission) 을 조정하도록 설계 되었다. 그런데, 쿠버네티스는 다음과 같이 네가지의 Role 관련 리소스를 가지고 있다. 그 차이는 다음과 같다. ClusterRole – 전체 클러스터에 적용하기 위한 역할(Role) 에 할당된 허가권(Permission) ClusterRoleBinding – 특정 계정(Account) 에 ClusterRole 을 바인딩 Role – 특정 네임스페이스에 적용하기 위한 역할(Role) 에 할당된 허가권(Permission) RoleBinding – 특정 계정(Account) 에 Role 을 바인딩 RBAC 을 적용하기 위해서는 계정이 필요하다. 이 계정은 쿠버네티스의 사용자를 말하는것이 아닌 쿠버네티스에서 운영되는 자원에 대한 계정을 말한다. 예를들어 ingress-nginx 라는 계정을 […]
Istio, Pod CrashLoopBackOff 해결하기
Istio 를 설치하고 Pod 를 생성했는데, 다음과 같이 오류가 발생했다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
]$ kubectl describe pod/employee-producer-866cfb8cf8-s2qk4 Init Containers: istio-init: Container ID: containerd://eb85c7971088c72e64b432a38f419a392182a44735281993c0c2b44460acd8fc Image: docker.io/istio/proxyv2:1.13.1 Image ID: docker.io/istio/proxyv2@sha256:099ee79c150829471270a14520506b83117bb7448cc80ba215617785237c1eb0 Port: <none> Host Port: <none> Args: istio-iptables .... State: Waiting Reason: CrashLoopBackOff Last State: Terminated Reason: Error Exit Code: 255 Started: Mon, 28 Feb 2022 13:07:52 +0900 Finished: Mon, 28 Feb 2022 13:07:52 +0900 ... |
istio-init 컨테이너가 오류가 발생한 것을 알 수 있다. Pod 안에 컨테이너가 여러개일 경우에 컨테이너 로그를 봐야하는데 다음과 같이 Pod 에 속한 컨테이너 로그를 볼수 있다.
1 2 3 4 5 6 7 8 |
]$ kubectl logs employee-producer-866cfb8cf8-spnqs -c istio-init COMMIT 2022-02-28T04:16:59.895565Z info Running command: iptables-restore --noflush /tmp/iptables-rules-1646021819895421411.txt3256082129 2022-02-28T04:16:59.896995Z error Command error output: xtables parameter problem: iptables-restore: unable to initialize table 'nat' Error occurred at line: 1 Try `iptables-restore -h' or 'iptables-restore --help' for more information. 2022-02-28T04:16:59.897030Z error Failed to execute: iptables-restore --noflush /tmp/iptables-rules-1646021819895421411.txt3256082129, exit status 2 |
이 문제는 istio cni 컴포넌트를 함께 설치해주면 된다. 보통 Istio 를 설치할때에 Profile 만 지정하는데, demo 프로파일에 경우에 CNI 를 설치하지 않는다. 다음과 같이 재설치를 해준다.
1 2 |
]$ istioctl x uninstall --purge # 삭제 ]$ istioctl install --set profile=demo --set components.cni.enabled=true -y |
이렇게 CNI 를 활성화해서 재설치를 하면 문제없이 작동 된다. 문제점 여기서 한가지 문제가 있다. CNI 는 […]
Istio 설치
Istio 는 쿠버네티스의 Network 레벨의 Mesh 서비스다. 비교하자면 Netflix OSS 에 Ribbon 과 비슷하다고 볼 수 있다. Istio 설치 방법 Istio 설치 방법은 다양하다. 처음에 Istio 를 시작할때에 가장 헷깔리는 것이 바로 설치 방법이다. 구글에서 검색을 하면 설치방법이 나오지만 읽어보면 제각각인 이유가 다양한 설치 방법 때문이다. 그래서인지 Istio 홈페이지에서 다양한 설치 방법을 적어놨는데 대략 3가지 방법이 많이 쓰인다. Install with Istioctl Install with Helm Install Istio Operator 여기서는 Istoctl 을 이용해 설치하는 법을 다룬다. 이 방법은 다음 문서에 잘 나와 […]
쿠버네티스 curl 사용하기
쿠버네티스에서 클러스터내에서 Pod 에 데이터가 잘 나오는지를 확인하는 방법은 CURL 일 것이다. ClusterIP 로 IP 가 할당되면 클러스터내에서 접근이 가능한데 이때에 다음과 같이 사용하면 된다.
1 2 3 |
$ kubectl run curl -it --rm --image curlimages/curl -- sh If you don't see a command prompt, try pressing enter. / $ |
curl 을 비롯한 ping, nslookup 도 가능하다.
Calico Metrics 모니터링 하기
Calico 는 쿠버네티스(Kubernetes) 의 CNI 다. 쉽게 말해서 쿠버네티스의 네트워킹을 가능하게 해준다. 설치도 쉽게 할수 있는데, 프로메테우스에서 Calico 모니터링을 하기 위해서는 추가적인 작업이 필요한데 여기에 대해서 알아본다. calicoctl calicoctl 을 설치해야 한다. 이 파일은 바이너리이며 wget, curl 명령어를 이용해서 설치가 가능하다. 설치를 한 후에 이것을 사용하기 위해서는 다음과 같이 환경변수를 설정해 준다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$ export DATASTORE_TYPE=kubernetes $ export KUBECONFIG=~/.kube/config $ calicoctl get nodes NAME kworker1.systemv.local kworker2.systemv.local kworker3.systemv.local $ calicoctl get workloadendpoints WORKLOAD NODE NETWORKS INTERFACE dnsutils kworker2.systemv.local 10.31.168.71/32 calib3c61c3cba9 springboot-deployment-77db875f78-9fshx kworker3.systemv.local 10.31.4.57/32 cali11c98587cc4 springboot-deployment-77db875f78-km8rd kworker1.systemv.local 10.31.20.48/32 cali712f16523f2 springboot-deployment-77db875f78-nj7t7 kworker1.systemv.local 10.31.20.57/32 calibcff04191b7 $ calicoctl get ippools NAME CIDR SELECTOR default-ipv4-ippool 10.31.0.0/16 all() |
calicoctl 명령어는 다양한 질의를 할 수 있다. Calico CRD Calico 설치를 메니페스트로 설치를 하게 되면 CRD 가 생성되면서 CRD 에 정의된 오브젝트가 함께 생성된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
$ kubectl get crd | grep calico bgpconfigurations.crd.projectcalico.org 2021-04-18T17:42:07Z bgppeers.crd.projectcalico.org 2021-04-18T17:42:07Z blockaffinities.crd.projectcalico.org 2021-04-18T17:42:08Z caliconodestatuses.crd.projectcalico.org 2022-01-28T16:00:01Z clusterinformations.crd.projectcalico.org 2021-04-18T17:42:08Z felixconfigurations.crd.projectcalico.org 2021-04-18T17:42:08Z globalnetworkpolicies.crd.projectcalico.org 2021-04-18T17:42:08Z globalnetworksets.crd.projectcalico.org 2021-04-18T17:42:08Z hostendpoints.crd.projectcalico.org 2021-04-18T17:42:08Z ipamblocks.crd.projectcalico.org 2021-04-18T17:42:09Z ipamconfigs.crd.projectcalico.org 2021-04-18T17:42:09Z ipamhandles.crd.projectcalico.org 2021-04-18T17:42:09Z ippools.crd.projectcalico.org 2021-04-18T17:42:09Z ipreservations.crd.projectcalico.org 2022-01-28T16:00:02Z kubecontrollersconfigurations.crd.projectcalico.org 2021-04-18T17:42:09Z networkpolicies.crd.projectcalico.org 2021-04-18T17:42:09Z networksets.crd.projectcalico.org 2021-04-18T17:42:10Z |
이것을 언급하는 […]
쿠버네티스 secret 파일 저장하기
쿠버네티스의 Secret 은 암호화해서 데이터를 저장하는데, 파일도 저장할 수 있다. 바이너리 파일이던 텍스트 파일이던 모두 base64 인코딩 스트링으로 저장이된다. 이것을 파일로 저장하는 방법에 대해서 간단하게 알아본다. Prometheus 설정 Secret Pormetheus 를 오퍼레이터(Operator) 로 설치를 했을 경우에 다음과 같은 Secret 을 볼 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
$ kubectl get secret prometheus-prometheus-kube-prometheus-prometheus -n monitoring -o yaml apiVersion: v1 data: prometheus.yaml.gz: H4sIAAAAAAAA/+ydz4+jNhTH7/krfNjDzFYZdraXijmttJV66G5X7bGqLMe8JN4Y27JNOqOq/3uFYxJIIBtmWCZp3g0wfjz/4H2+NmAWUs+YTCeEwJrJgnmhFRXKg10zmZIf37kJIY5bZuDgMDx6sIpJKtkMpCuNEGKszsEvoXApybUSXluhFsnu8HRVzGBa299t7hmgFowUnKXkzc2X3z7Szx8+/Xw7sYUEOhcSXDqZkgQ8rxlPylSXtFo/cuFpmS3YnL5L3t49sVxOYqG5VnOxCNf6qmdUsRxS4sCuBYdPm/Ilp5WTSbA+Z4otwCbvJoQstdK2qjwyZ9LBhJAym1XgwVGX7S5PyJRYLSEloDKjhfKb6iodcoZxiPUfj1Q701ojTAjJwVvBHTXML1OSxN0JIRaCH83rOV1YDo3mDbUQtjyzC/CbxJRQ6nNDa21XVVYwxHjZr1KyAjAhc6tlSnPwjNYrYFPPm/MoM+a0M40FB8pvM1hYwGNKbvZbxHnGV412uX3wthjSZwsSWGjXHn7XM1W+79we3EcHck5jN+nn6EHOytvSwwH8rLo6Ndr6qjttr7L03kz/hll3Xz1ikWWZBedo7MYrobLembYOOTDMMq9tSh7qHn7WGTzc3L29jQeNZBxyUD4lb/65/7flPlI6g/Mtzxed9SuO0Vmf0myDWVvN1NJONlj12m3JmjZjch+LRmdd1noWtrTEtfJMKLBdNrcnDFjqKoK3NeB079yqqxxmOOXuq/oX7STGkrllSMx1VshSNNyH3SpilOn58XptmIkd9c3NH798+P3jbcNWjD4b6NF94pE//xqA8UaU+UYFfAZzVkgfdNoSStfLpikze+mi/c3ZQjnghQXqVsLQNVgxf9r5RcjG9Vj+nZshjbMgulKSrJlNbKESB9yCd8nuxDuhk1htjHNdKJ9wdsdt6dsMmAVLvV6BepalkPNClArXudEK4m1zMk6b2SqWbvvU4OA3Vq9FBj2h38hVl1abTKNg350vI5H5yPxLY/4AQa7rcpvwcPdDd//pJzmO3vlXpze4tpApN6LaCB64J+chvzaqf6f5h9iGVzL1cMKQfjcrdaZIRMQj4q8C8V/17NdyY1TCn3L/Xx3oF5bNmWL43OB53K4nCk2Fcp4p3pON37Azwkz9oQfbWPCCUuxD+CZ2NpzAR9Ij6S+O9DiB/wLOhv2yzayWEux0/Of1zQH286b0Y9zGWftzGN93dCkc7+N4H1UAqgAc7+N4v0OHgOcZTu1fOvrLVkTYI+wR9gh7hD3CvgP2xurHJ6T9pdM+NCPiHnGPuEfcI+4R9x24d3wJWSHx0QIqjhcqjm1PQtWBqgNVB6oOVB2oOtpVhwTfIjdiREa18T9SG2O8Jhh71OCyY/WT6y+Y6pmGd/CELxJRdKDoQNFxFqKjHgtG+y7xxPt/+xp9q/Kon4DqpUW93L+Oemn//iHhLFsLF9a+QX2D+gb1Deob1Deob1DfoL55pr55f1b6xlg9A4fqBtUNqpvXVgOoblDdoLpBdXOJ6kYbCCFgvIdPjdUrXrou5k6+7K02zsF6FxUI3V2SHlshNMuFc0IrylmMj7VFN0+ow8tRMb0lywH+D994qWoB33XBlTBRsaBiec3FM/D9kva/aeAiVefDy++4GNV5EhN/bYFwR7gj3HFlrCH47jzzUM2NvNLo/ULovTffjktMfvPpQ7N3jcLU8+UP8hR5emk8HTrAjDXbf9Vcr22WEWQKj2W0fL1fUtYn5y+H9i8bq3e1wZWM0fELzvMrD/Iaed0aQvALzoFIHf4zLFR45hy2D85qBNWQlFndIMfhz7ErY3FV4WgkvKJgLMzFY0qSzY3f5OwRqndxvY3se2w/oDshzAi6ButCodbvY2kOCt7Kk1ainHhjtNTZ0V9yD+BDB9cOZ3X/CwAA///mZWEHdn0AAA== kind: Secret metadata: annotations: generated: "true" creationTimestamp: "2022-01-29T16:06:35Z" labels: managed-by: prometheus-operator name: prometheus-prometheus-kube-prometheus-prometheus namespace: monitoring ownerReferences: - apiVersion: monitoring.coreos.com/v1 blockOwnerDeletion: true controller: true kind: Prometheus name: prometheus-kube-prometheus-prometheus uid: 6b8415cb-b99a-4ac4-8bc1-a6175265fd1c resourceVersion: "841303" uid: 18933ea2-4dd8-464c-a61b-69513f7a807c type: Opaque |
data 필드를 보면 prometheus.yaml.gz 파일이름이 보이고 내용이 base64 스트링이 보인다. 이 prometheus.yaml.gz 파일을 받기 위해서는 간단히 bas64 스트링을 디코딩하고 나오는 스트링을 그냥 파일명으로 저장하면 된다.
1 2 3 |
$ echo "H4sIAAAAAAAA/+ydz4+jNhTH7/krfNjDzFYZdraXijmttJV66G5X7bGqLMe8JN4Y27JNOqOq/3uFYxJIIBtmWCZp3g0wfjz/4H2+NmAWUs+YTCeEwJrJgnmhFRXKg10zmZIf37kJIY5bZuDgMDx6sIpJKtkMpCuNEGKszsEvoXApybUSXluhFsnu8HRVzGBa299t7hmgFowUnKXkzc2X3z7Szx8+/Xw7sYUEOhcSXDqZkgQ8rxlPylSXtFo/cuFpmS3YnL5L3t49sVxOYqG5VnOxCNf6qmdUsRxS4sCuBYdPm/Ilp5WTSbA+Z4otwCbvJoQstdK2qjwyZ9LBhJAym1XgwVGX7S5PyJRYLSEloDKjhfKb6iodcoZxiPUfj1Q701ojTAjJwVvBHTXML1OSxN0JIRaCH83rOV1YDo3mDbUQtjyzC/CbxJRQ6nNDa21XVVYwxHjZr1KyAjAhc6tlSnPwjNYrYFPPm/MoM+a0M40FB8pvM1hYwGNKbvZbxHnGV412uX3wthjSZwsSWGjXHn7XM1W+79we3EcHck5jN+nn6EHOytvSwwH8rLo6Ndr6qjttr7L03kz/hll3Xz1ikWWZBedo7MYrobLembYOOTDMMq9tSh7qHn7WGTzc3L29jQeNZBxyUD4lb/65/7flPlI6g/Mtzxed9SuO0Vmf0myDWVvN1NJONlj12m3JmjZjch+LRmdd1noWtrTEtfJMKLBdNrcnDFjqKoK3NeB079yqqxxmOOXuq/oX7STGkrllSMx1VshSNNyH3SpilOn58XptmIkd9c3NH798+P3jbcNWjD4b6NF94pE//xqA8UaU+UYFfAZzVkgfdNoSStfLpikze+mi/c3ZQjnghQXqVsLQNVgxf9r5RcjG9Vj+nZshjbMgulKSrJlNbKESB9yCd8nuxDuhk1htjHNdKJ9wdsdt6dsMmAVLvV6BepalkPNClArXudEK4m1zMk6b2SqWbvvU4OA3Vq9FBj2h38hVl1abTKNg350vI5H5yPxLY/4AQa7rcpvwcPdDd//pJzmO3vlXpze4tpApN6LaCB64J+chvzaqf6f5h9iGVzL1cMKQfjcrdaZIRMQj4q8C8V/17NdyY1TCn3L/Xx3oF5bNmWL43OB53K4nCk2Fcp4p3pON37Azwkz9oQfbWPCCUuxD+CZ2NpzAR9Ij6S+O9DiB/wLOhv2yzayWEux0/Of1zQH286b0Y9zGWftzGN93dCkc7+N4H1UAqgAc7+N4v0OHgOcZTu1fOvrLVkTYI+wR9gh7hD3CvgP2xurHJ6T9pdM+NCPiHnGPuEfcI+4R9x24d3wJWSHx0QIqjhcqjm1PQtWBqgNVB6oOVB2oOtpVhwTfIjdiREa18T9SG2O8Jhh71OCyY/WT6y+Y6pmGd/CELxJRdKDoQNFxFqKjHgtG+y7xxPt/+xp9q/Kon4DqpUW93L+Oemn//iHhLFsLF9a+QX2D+gb1Deob1Deob1DfoL55pr55f1b6xlg9A4fqBtUNqpvXVgOoblDdoLpBdXOJ6kYbCCFgvIdPjdUrXrou5k6+7K02zsF6FxUI3V2SHlshNMuFc0IrylmMj7VFN0+ow8tRMb0lywH+D994qWoB33XBlTBRsaBiec3FM/D9kva/aeAiVefDy++4GNV5EhN/bYFwR7gj3HFlrCH47jzzUM2NvNLo/ULovTffjktMfvPpQ7N3jcLU8+UP8hR5emk8HTrAjDXbf9Vcr22WEWQKj2W0fL1fUtYn5y+H9i8bq3e1wZWM0fELzvMrD/Iaed0aQvALzoFIHf4zLFR45hy2D85qBNWQlFndIMfhz7ErY3FV4WgkvKJgLMzFY0qSzY3f5OwRqndxvY3se2w/oDshzAi6ButCodbvY2kOCt7Kk1ainHhjtNTZ0V9yD+BDB9cOZ3X/CwAA///mZWEHdn0AAA==" | base64 -d > prometheus.yaml.gz $ file prometheus.yaml.gz prometheus.yaml.gz: gzip compressed data, original size modulo 2^32 32118 |
간단하게 echo “<encoded-value>” | base64 -d prometheus.yaml.gz 으로 보면 된다. […]
쿠버네티스에 프로메테우스(Prometheus) 오퍼레이터 설치하기
프로메테우스(Prometheus)는 모니터링 시스템을 말한다. 프로메테우스는 파일 기반의 타임시리즈(Time-Series) 데이터베이스다. 시스템의 메트릭스들을 수집하기 위해서는 익스포터(Exportor) 를 설치해야 한다. 이외에도 알람을 전달해주는 AlertManager 도 있는데, 전체적인 아키텍쳐는 다음과 같다. 프로메테우스는 쿠버네티스에서도 설치가 가능한데, 이글은 쿠버네티스에 프로메테우스 설치에 대한 글이다. 환경 환경은 다음과 같다. Kubernetes 버전: 1.20 Kubernetes Nodes: Master 3개, Worker 3개 Prometheus 설치 방법: Helm Operator 설치 프로메테우스(Prometheus) 설치는 매우 다양한데, 검색을 해보면 Helm 을 이용한 방법 그중에서도 오퍼레이터(Operator) 를 이용한 방법이 많이 소개 되어 있다. 여기서도 이 오퍼레이터를 이용한 방법을 […]