diff --git "a/_posts/2023-12-25-2023\353\205\204-\355\232\214\352\263\240.md" "b/_posts/2023-12-25-2023\353\205\204-\355\232\214\352\263\240.md" index 543c4c5..079e08c 100644 --- "a/_posts/2023-12-25-2023\353\205\204-\355\232\214\352\263\240.md" +++ "b/_posts/2023-12-25-2023\353\205\204-\355\232\214\352\263\240.md" @@ -18,6 +18,7 @@ tags: [ 커리어 커피챗, 커뮤니티, + 대전 개발자 스터디, ] date: 2023-12-25 16:30:00 +0900 --- @@ -172,7 +173,7 @@ K-DEVCON Daejeon 에서 진행한 12월 행사에서 운영자로서의 회고 ### 공부 할 것 -K-DEVCON 대전 오프라인 스터디에서는 +K-DEVCON 대전 개발자 스터디에서는 - 데이터 중심 애플리케이션 설계 - 시스템 디자인 2 @@ -232,3 +233,7 @@ K-DEVCON Daejeon과 함께 GDG Daejeon 에서도 많은 활동을 해나갈 수 올해를 마무리 하면서 개인 명함을 만들어 봤다. ![개인%20명함%20디자인](/assets/images/2023-12-25-2023년-회고/개인%20명함%20디자인.jpeg) + +## 기타 + +대전 개발자 스터디 에 관심이 있다면 [구글 폼](http://k-devcon.web.app/daejeon-membership) 을 통해 신청할 수 있다. diff --git a/_posts/2024-08-24-mysql-architecture.md b/_posts/2024-08-24-mysql-architecture.md index 1cf3fe4..d881552 100644 --- a/_posts/2024-08-24-mysql-architecture.md +++ b/_posts/2024-08-24-mysql-architecture.md @@ -16,13 +16,13 @@ tags: flow, thread, thread pool, - metadata + metadata, ] date: 2024-08-24 23:59:59 +0900 toc: true --- -[K-DEVCON](https://k-devcon.com) 대전 오프라인 스터디에서 Real Mysql 책으로 스터디를 진행해보기로 했다. +[K-DEVCON](https://k-devcon.com) 대전 개발자 스터디에서 Real Mysql 책으로 스터디를 진행해보기로 했다. 발표하면서 준비한 내용을 블로그로도 옮겨보려고 한다. @@ -30,6 +30,8 @@ toc: true 이 글의 내용은 Mysql 8.0 에서 InnoDB 를 기준으로 정리되었다. 이 글은 정리글이기에 생략이 있으며, 책에서는 이전 버전이나 다른 스토리지 엔진에 대해서도 다루기도 하고 더 자세한 내용들을 다루고 있다. 책의 구성이 이미 안다는것을 전제하에 진행된 부분들도 있어 해당 부분에 대해서 보충설명을 넣기도 하였다. +참고로 대전 개발자 스터디 에 관심이 있다면 [구글 폼](http://k-devcon.web.app/daejeon-membership) 을 통해 신청할 수 있다. + --- # 아키텍처 - Real MySQL 스터디 1회차 @@ -254,14 +256,14 @@ MySQL 은 **스레드 기반**으로 작동한다. 스레드는 크게 Foregroun ### 체인지 버퍼 -레코드 INSERT 되거나 UPDATE 될 때 변경해야 할 인덱스 페이지가 버퍼 풀에 있으면 바로 업데이트를 수행하지만 그렇지 않고 디스크로부터 읽어와서 업데이트해야 한다면 이를 즉시 실행하지 않고 임시 공간(= 체인지 버퍼)에 저장해 두고 바로 사용자에게 결과를 반환하는 형태로 성능을 향상시킨다. -\* 유니크 인덱스는 체인지 버퍼를 사용할 수 없다. 반드시 중복 여부를 체크해야 하기 때문 +레코드 INSERT 되거나 UPDATE 될 때 변경해야 할 인덱스 페이지가 버퍼 풀에 있으면 바로 업데이트를 수행하지만 그렇지 않고 디스크로부터 읽어와서 업데이트해야 한다면 이를 즉시 실행하지 않고 임시 공간(= 체인지 버퍼)에 저장해 두고 바로 사용자에게 결과를 반환하는 형태로 성능을 향상시킨다. \* 유니크 인덱스는 체인지 버퍼를 사용할 수 없다. 반드시 중복 여부를 체크해야 하기 때문 ### 어댑티브 해시 인덱스 InnoDB 스토리지 엔진에서 사용자가 자주 요청하는 데이터에 대해 자동으로 생성하는 인덱스 다음의 경우에 유용하다. + - 디스크의 데이터가 InnoDB 버퍼 풀 크기와 비슷한 경우 (디스크 읽기가 많지 않은 경우) - 동등 조건 검색(동등 비교와 IN 연산자)이 많은 경우 - 쿼리가 데이터 중에서 일부 데이터에만 집중되는 경우 @@ -275,6 +277,7 @@ SHOW ENGINE INNODB STATUS 명령어를 통해서 사용 빈도를 확인할 수 스토리지 엔진은 버퍼 풀이라는 거대한 메모리 공간을 페이지로 나누어 관리한다. 버퍼 풀은 크게 아래의 3개의 자료 구조로 관리한다. + - LRU 리스트 (Least Recently Used) - 플러시 리스트 (Flush) - 프리 리스트 (Free) : 비어있는 공간을 관리 @@ -293,7 +296,7 @@ InnoDB의 LRU 리스트는 2개의 LRU 리스트가 결합된 형태이다. 데 이 구조의 장점은 무엇일까? 자주 사용되지 않는 데이터가 LRU list에 추가되었을 때, 더 빨리 방출될 수 있을 것이다. -### 버퍼 풀과 리두 로그 +### 버퍼 풀과 리두 로그 버퍼 풀은 데이터 캐시와 쓰기 버퍼링 역할을 한다. 버퍼 풀의 메모리 용량만 늘릴 경우에는 캐시 기능만 향상된다. 쓰기 버퍼링 기능까지 향상시키려면 리두 로그의 크기도 적절히 설정해줘야 한다. @@ -398,8 +401,6 @@ transaction isolation levels described by the SQL:1992 standard ![transaction-isolation-level-compare-2](/assets/images/2024-08-24-mysql-architecture/transaction-isolation-level-compare-2.png) - - ### ACID - 원자성 (atomicity) : 부분적으로 실행되다가 중단되지 않는 것을 보장한다는 것을 의미 @@ -417,7 +418,7 @@ transaction isolation levels described by the SQL:1992 standard ## 자동 데드락 감지 -내부적으로 잠금 대기 목록을 관리한다. 데드락 감지 스레드가 주기적으로 잠금 대기 목록을 검사해 교착 상태에 빠진 트랜잭션을 찾아 그 중 하나를 강제 종료한다. +내부적으로 잠금 대기 목록을 관리한다. 데드락 감지 스레드가 주기적으로 잠금 대기 목록을 검사해 교착 상태에 빠진 트랜잭션을 찾아 그 중 하나를 강제 종료한다. innodb_table_locks 시스템 변수를 활성화 하면 스토리지 엔진 내부의 레코드 잠금뿐만 아니라 테이블 레벨의 잠금까지 감지할 수 있다. @@ -460,6 +461,3 @@ InnoDB에는 손실이나 장애로부터 데이터를 보호하기 위한 여 - 실행된 쿼리중 오래걸리는 쿼리를 기록 - long_query_time (default : 10s) - pt-query-digest 스크립트를 사용하면 쉽게 분석가능 - - - diff --git a/_posts/2024-09-07-mysql-lock-and-transaction.md b/_posts/2024-09-07-mysql-lock-and-transaction.md index c6567d1..d138a23 100644 --- a/_posts/2024-09-07-mysql-lock-and-transaction.md +++ b/_posts/2024-09-07-mysql-lock-and-transaction.md @@ -19,7 +19,7 @@ date: 2024-09-07 23:59:59 +0900 toc: true --- -[K-DEVCON](https://k-devcon.com) 대전 오프라인 스터디에서 Real Mysql 책으로 스터디를 진행해보기로 했다. +[K-DEVCON](https://k-devcon.com) 대전 개발자 스터디에서 Real Mysql 책으로 스터디를 진행해보기로 했다. 발표하면서 준비한 내용을 블로그로도 옮겨보려고 한다. @@ -27,6 +27,8 @@ toc: true 이 글의 내용은 Mysql 8.0 에서 InnoDB 를 기준으로 정리되었다. 이 글은 정리글이기에 생략이 있으며, 책에서는 이전 버전이나 다른 스토리지 엔진에 대해서도 다루기도 하고 더 자세한 내용들을 다루고 있다. 책의 구성이 이미 안다는것을 전제하에 진행된 부분들도 있어 해당 부분에 대해서 보충설명을 넣기도 하였다. +참고로 대전 개발자 스터디 에 관심이 있다면 [구글 폼](http://k-devcon.web.app/daejeon-membership) 을 통해 신청할 수 있다. + --- # 아키텍처 - Real MySQL 스터디 2회차 diff --git a/_posts/2024-09-28-mysql-compression-and-encryption.md b/_posts/2024-09-28-mysql-compression-and-encryption.md index d5d899e..f6ee2ff 100644 --- a/_posts/2024-09-28-mysql-compression-and-encryption.md +++ b/_posts/2024-09-28-mysql-compression-and-encryption.md @@ -19,12 +19,14 @@ date: 2024-09-28 23:59:59 +0900 toc: true --- -[K-DEVCON](https://k-devcon.com) 대전 오프라인 스터디에서 Real Mysql 책으로 스터디를 진행해보기로 했다. +[K-DEVCON](https://k-devcon.com) 대전 개발자 스터디에서 Real Mysql 책으로 스터디를 진행해보기로 했다. 발표하면서 준비한 내용을 블로그로도 옮겨보려고 한다. 이 글의 내용은 Mysql 8.0 에서 InnoDB 를 기준으로 정리되었다. 이 글은 정리글이기에 생략이 있으며, 책에서는 이전 버전이나 다른 스토리지 엔진에 대해서도 다루기도 하고 더 자세한 내용들을 다루고 있다. 책의 구성이 이미 안다는것을 전제하에 진행된 부분들도 있어 해당 부분에 대해서 보충설명을 넣기도 하였다. +참고로 대전 개발자 스터디 에 관심이 있다면 [구글 폼](http://k-devcon.web.app/daejeon-membership) 을 통해 신청할 수 있다. + --- # 압축 diff --git a/_posts/2024-11-03-mysql-full-scan-query-pattern.md b/_posts/2024-11-03-mysql-full-scan-query-pattern.md index 8304a40..1ff79fd 100644 --- a/_posts/2024-11-03-mysql-full-scan-query-pattern.md +++ b/_posts/2024-11-03-mysql-full-scan-query-pattern.md @@ -27,6 +27,8 @@ toc: true 이 글의 내용은 Mysql 8.0 에서 InnoDB 를 기준으로 정리되었다. 이 글은 정리글이기에 생략이 있으며, 책에서는 이전 버전이나 다른 스토리지 엔진에 대해서도 다루기도 하고 더 자세한 내용들을 다루고 있다. 책의 구성이 이미 안다는것을 전제하에 진행된 부분들도 있어 해당 부분에 대해서 보충설명을 넣기도 하였다. +참고로 대전 개발자 스터디 에 관심이 있다면 [구글 폼](http://k-devcon.web.app/daejeon-membership) 을 통해 신청할 수 있다. + --- # MySQL 풀스캔 쿼리 패턴 및 튜닝 diff --git a/_posts/2024-11-06-java-guava-ratelimiter.md b/_posts/2024-11-06-java-guava-ratelimiter.md index 2fa980c..24cb663 100644 --- a/_posts/2024-11-06-java-guava-ratelimiter.md +++ b/_posts/2024-11-06-java-guava-ratelimiter.md @@ -46,13 +46,11 @@ class documentation : [https://guava.dev/releases/snapshot-jre/api/docs/com/goog 아래는 초당 2회 api 를 호출하도록 한 테스트 코드이다. (예제이기 떄문에 그냥 `print` 메소드를 사용하였다.) ```java -public class RateLimiterTest { - RateLimiter rateLimiter = RateLimiter.create(2); +RateLimiter rateLimiter = RateLimiter.create(2); - for (int i = 0; i < Integer.MAX_VALUE; i++) { - rateLimiter.acquire(); - System.out.println(i); - } +for (int i = 0; i < Integer.MAX_VALUE; i++) { + rateLimiter.acquire(); + System.out.println(i); } ``` diff --git a/_posts/2024-11-13-deploy-application-using-k8s.md b/_posts/2024-11-13-deploy-application-using-k8s.md new file mode 100644 index 0000000..92f96e4 --- /dev/null +++ b/_posts/2024-11-13-deploy-application-using-k8s.md @@ -0,0 +1,293 @@ +--- +layout: post +title: "[k8s] 쿠버네티스로 어플리케이션 배포하기" +categories: [스터디-인프라, 개발] +tags: + [ + k8s, + kubernetes, + jenkins, + docker, + container, + deployment, + service, + private registry, + ingress, + ingress controller, + ingress class, + load balancer, + lb, + metallb, + ] +date: 2024-11-13 18:00:00 +0900 +toc: true +--- + +이 글에서는 k8s (microk8s) 에서 어플리케이션를 배포해본 경험을 정리해본다. + +틈틈이 테스트를 위한 환경을 온프레미스로 구축하고 있다. + +처음으로 k8s에 어플리케이션을 배포하는 사람에게 도움이 되기를 바란다. + +## 목표 + +오늘의 목표는 브라우저에서 `admin.jonghoonpark.com` 이라는 도메인에 접속했을 때 k8s로 배포된 어플리케이션에 접속이 되게 하는 것이다. + +![plan](/assets/images/2024-11-13-deploy-react-project-using-k8s/plan.png) + +## host 파일 수정 + +실제로 도메인을 연결해도 되지만 테스트 목적이기 떄문에 host를 수정하는 방향으로 진행하였다. +admin.jonghoonpark.com 이 10.8.0.4 를 바라보는것 처럼 되도록 세팅하였다. + +ubuntu 에서는 `/etc/hosts` 파일을 수정하였고, mac에서는 [Gas Mask](https://github.com/2ndalpha/gasmask) 라는 프로그램을 사용하여 host 파일을 수정하였다. (오늘 처음 써봤는데 쉽게 사용할 수 있어서 좋았다.) + +``` +10.8.0.4 admin.jonghoonpark.com +``` + +## k8s에서 private registry에 접근하기 위한 설정 + +로컬에서 docker 이미지를 빌드하였고, 잘 동작하는 것을 확인하였다. + +docker 이미지는 private registry 에 푸시하였다. (nexus 사용) + +deployment 파일을 통해 pod에 어떤 docker 이미지를 사용할지 지정하게 된다. 따라서 관련 설정을 먼저 해둔다. + +### private registry 에 접근하기 위한 secret 생성 + +[kubectl create secret docker-registry](https://kubernetes.io/docs/reference/kubectl/generated/kubectl_create/kubectl_create_secret_docker-registry/) + +private registry 에 접속하기 위한 정보를 secret으로 만들어 둔다. (docker-server 에는 포트 정보도 포함해야 한다. e.g. 10.8.0.4:32000) + +```sh +kubectl create secret docker-registry NAME \ + --docker-server=host \ + --docker-username=user \ + --docker-password=password +``` + +secret을 만들때 docker-email 옵션이 필수 필요한 시절이 있었던것 같다. nexus 에는 이메일 정보가 따로 없기 때문에 생략하였는데 따로 문제는 없었다. (k8s v1.31.2 버전 사용중) + +### insecure registry 일 경우 + +insecure registry 일 경우, docker 쪽에서도 세팅이 필요하지만 microk8s 에서도 세팅이 필요하다. + +microk8s 공식 문서 중 [How to work with a private registry](https://microk8s.io/docs/registry-private) 문서를 참고하여 세팅한다. + +```sh +sudo mkdir -p /var/snap/microk8s/current/args/certs.d/10.8.0.4:32000 +sudo vim /var/snap/microk8s/current/args/certs.d/10.8.0.4:32000/hosts.toml +``` + +```conf +# /var/snap/microk8s/current/args/certs.d/10.8.0.4:32000/hosts.toml +server = "http://10.8.0.4:32000" + +[host."http://10.141.241.175:32000"] +capabilities = ["pull", "resolve"] +``` + +`10.8.0.4:32000` 부분을 자신의 registry 에 맞게 수정해주면 된다. + +만약 insecure 관련 세팅이 제대로 되지 않았다면 `http: server gave HTTP response to HTTPS client` 와 같은 에러가 발생된다. + +## deployment 설정 + +[deployment](https://kubernetes.io/ko/docs/concepts/workloads/controllers/deployment/) 는 파드에 대한 선언적 업데이트를 제공한다. + +deployment 는 다음과 같이 작성하였다. + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: admin-web-deployment +spec: + replicas: 1 + selector: + matchLabels: + app: admin-web + template: + metadata: + labels: + app: admin-web + spec: + containers: + - name: admin-web-container + image: 10.8.0.4:32000/admin-web:latest + ports: + - containerPort: 5173 + resources: + limits: + memory: "2048Mi" + cpu: "500m" + requests: + memory: "1024Mi" + cpu: "500m" + imagePullSecrets: + - name: private-registry-secret +``` + +위에서 생성한 private registry 의 secret을 사용한다. + +vite 기반 어플리케이션을 샘플로 사용하여 5173 포트를 사용하게 되었다. 상황에 맞게 포트와 리소스를 설정해주면 된다. + +## service 설정 + +[service](https://kubernetes.io/ko/docs/concepts/services-networking/service/)는 파드 집합에서 실행중인 애플리케이션을 네트워크 서비스로 노출하는 추상화하는데 사용된다. + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: admin-web-service +spec: + selector: + app: admin-web + ports: + - protocol: TCP + port: 5173 + targetPort: 5173 + type: ClusterIP +``` + +팟에서 5173 포트를 사용하였기 때문에 service 에서는 5173 포트를 사용하였다. +`targetPort` 가 pod의 port이고, `port` 가 서비스에서 노출할 port이다. + +여기까지 따라했다면 아마 포트포워딩을 통해서 pod에 접근을 할 수는 있을 것이다. +이제 ingress 설정을 통해 포트포워딩 없이도 접근 가능한 상태로 만들어보자. + +## ingress 설정 + +[ingress](https://kubernetes.io/ko/docs/concepts/services-networking/ingress/)는 쿠버네티스 API를 통해 정의한 규칙에 기반하여 트래픽을 다른 백엔드에 매핑할 수 있게 하는데 사용된다. + +### ingress controller + +클러스터 내의 인그레스가 작동하려면, **ingress controller** 가 실행되고 있어야 한다. 적어도 하나의 인그레스 컨트롤러를 선택하여 이를 클러스터 내에 설치해야한다. + +#### nginx ingress + +ingress controller 는 다양하게 구현되어 있다. 이 글에서는 **nginx ingress** 를 사용하였다. + +다음 명령어로 설치할 수 있다. + +```sh +kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml +``` + +이후 아래와 같이 컨트롤러가 생성된 것을 확인할 수 있다. (아직 EXTERNAL-IP는 pending 상태이다.) + +```sh +$ kubectl get svc -n ingress-nginx +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +ingress-nginx-controller LoadBalancer 10.152.183.69 80:31118/TCP,443:30651/TCP +ingress-nginx-controller-admission ClusterIP 10.152.183.179 443/TCP +``` + +### ingress + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: admin-web-ingress + annotations: + nginx.ingress.kubernetes.io/rewrite-target: / +spec: + ingressClassName: nginx + rules: + - host: admin.jonghoonpark.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: admin-web-service + port: + number: 5173 +``` + +`admin.jonghoonpark.com` 도메인으로 들어오는 요청을 `admin-web-service` 서비스로 전달하도록 구성하였다. + +### ingress class + +인그레스를 처리하는 방식은 인그레스 컨트롤러에 따라 달라진다. 따라서 어떤 컨트롤러를 사용할 것인지 클래스 이름을 포함해줘야 한다. +여기서는 `ingressClassName: nginx` 를 통해 nginx 를 사용할 것이라고 명시해주었다. + +다음과 같이 IngressClass 도 생성해준다. + +```yaml +apiVersion: networking.k8s.io/v1 +kind: IngressClass +metadata: + name: nginx +spec: + controller: k8s.io/ingress-nginx +``` + +ingress class 를 설정하는 것을 놓치면 아래와 같은 에러를 마주할 수 있다. + +```sh +kubectl logs ingress-nginx-controller-546f9cf9bf-gtwn4 -n ingress-nginx +``` + +``` +"Ignoring ingress because of error while validating ingress class" ingress="default/admin-web-ingress" error="ingress does not contain a valid IngressClass" +``` + +여기까지 설정을 잘 따라왔다고 해도 아직은 `admin.jonghoonpark.com` 으로 어플리케이션에는 접근하지 못한다. (아직 EXTERNAL-IP는 pending 상태이기 때문이다.) 이를 해결하기 위해 load balancer를 추가해줘야한다. + +## load balancer 설정 + +마지막으로 load balancer를 설정해줘야 한다. + +load balancer와 ingress는 서로 보완적인 역할을 수행한다. +load balancer의 개념이 ingress 와 혼동이 되기도 하는데 정리해보자면 다음과 같은 차이를 가지고 있다. + +| 종류 | 특징 | +| ---------- | -------------------------------------- | +| 인그레스 | 애클러스터 내부에서 트래픽을 라우팅 | +| 로드밸런서 | 외부에서 트래픽을 받아 인그레스로 전달 | + +### metallb + +load balancer도 다양하게 구현되어 있다. 이 글에서는 [**metallb**](https://github.com/metallb/metallb) 를 사용하였다. + +다음 명령어로 설치할 수 있다. + +```sh +kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.8/config/manifests/metallb-native.yaml +``` + +설치한 후에는 ip address pool을 설정해줘야 한다. 나는 다음과 같이 설정해주었다. + +```yaml +apiVersion: metallb.io/v1beta1 +kind: IPAddressPool +metadata: + name: dev + namespace: metallb-system +spec: + addresses: + - 10.8.0.4/32 +``` + +address 에는 ingress controller 의 ip를 명시해주면 된다. (여기서는 한 ip 를 지정하였지만, 환경에 맞춰 여러 ip 범위를 지정할 수도 있다.) + +apply 해보면 ingress-nginx-controller 에 EXTERNAL-IP가 연결된 것을 볼 수 있다. + +```sh +$ kubectl get svc -n ingress-nginx +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +ingress-nginx-controller LoadBalancer 10.152.183.69 10.8.0.4 80:31118/TCP,443:30651/TCP +ingress-nginx-controller-admission ClusterIP 10.152.183.179 443/TCP +``` + +이제 처음 목표였던 `admin.jonghoonpark.com` 으로 애플리케이션에 접근할 수 있다. + +## 기타 + +- 대부분의 내용은 k8s 공식 도큐먼트를 참고하였다. +- ingress 설정 후에도 연결이 되지 않을 경우에는 로그를 확인해보자. 바로 위에서 사용한대로 `kubectl logs` 명령어로 로그를 확인해볼 수 있다. diff --git a/assets/images/2024-11-13-deploy-react-project-using-k8s/plan.png b/assets/images/2024-11-13-deploy-react-project-using-k8s/plan.png new file mode 100644 index 0000000..c95cf2c Binary files /dev/null and b/assets/images/2024-11-13-deploy-react-project-using-k8s/plan.png differ