블로그

[워밍업 클럽 4기 백엔드] 4주차 발자국

4주차 회고  학습 내용섹션 7. mock을 마주하는 자세mockito 어노테이션 별로 사용하는 방법과 용도를 알수 있게 되었다classist와 mockist 개념을 알게 되었고 어떤것을 중점을 나아갈지 생각해 보았다 섹션 8. 더 나은 테스트를 작성하기 위한 구체적 조언 @beforeEach에 넣는것을 아무 생각 없이 썼는데 테스트 환경에 영향을 주지 않는것으로 고려해서 써야한다는것을 알게 되었다여러가지 테스트 환경을 구성하는 방법에 대해 알게 되었다 섹션 9, 10 appendix , outrospring rest docs 를 예전에 써보았는데 다시한번 복습하는 시간 이었다앞으로 테스트를 어떤식으로 써야 할지 생각을 해보는 챕터였다 4주차 과제 실제 테스트를 해보면서 테스트 코드 작성하는 감을 잡을 수 있었다mockito 어노테이션을 정리하면서 해당 어노테이션을 알게 되었다각 레이어 별로 테스트를 어떻게 짜야할지 정리해 볼수 있었다  수료 후 느낀점 개발을 하면서 어떤식으로 코드리뷰를 해야하고 코드를 리펙토링을 해야할지 알게 되는 기회가 되어 좋았다 어떤 주제로 코드를 작성하고 테스트를 작성하는 방법에 대해 자세히 알수 있게 되었다 위에서 배운 내용을 실무적으로 적용을 해야할지 한번 생각을 해봐야겠다     

백엔드

워밍업클럽 - 4주차 발자국

일주일 동안 학습했던 내용을 요약해주세요.Helm과 Kustomize 비교하여 사용 - 2 ~ ArgoCD 빠르게 레벨업 3ArgoCD로 Kubernetes 정의를 깃헙에 코드로 관리할 수 있었다(주의할 점이 있었지만) 자동으로 인식해서 상태를 맞추고 누르면 배포까지 진행해준다니 신세계다ArgoCD의 Rollouts를 이용해서 BlueGreen, Canaray 배포를 편리하게할 수 있다무엇보다 ArgoCD의 시각화 UI가 직관적이라 배포 상태 파악이 쉬운 점이 큰 장점으로 다가왔다실습을 통해 Helm/Kustomize 등의 매니페스트 관리 도구를 비교하고 적절한 상황에서 활용할 수 있는 감을 익힘 일주일 간의 학습 내용에 대한 간단한 회고를 작성해 주세요.일주일 동안 스스로 칭찬하고 싶은 점, 아쉬웠던 점, 보완하고 싶은 점이 무엇인지 생각해 보세요.😀 다 들었다... 다음주에는 어떤 식으로 학습하겠다는 스스로의 목표를 세워봐도 좋아요.이제는 실전이다.. 프로젝트에 적용시켜보겠습니다 미션미션을 해결하는 과정을 요약해 주세요. 파드 상태를 kubectl을 통해 직접 확인이전에 만들었던 pv, pvc, namespace 삭제해야 제 컴퓨터는 버텼습니다.준비 상태가 확인되면 ArgoCD를 통해 버튼 클릭으로 배포 수행GitOps 흐름에 따라 리포지토리 수정 → 자동 감지 → 상태 동기화 → 배포 흐름을 체험  총 회고팀원들이 모두 열심히 하셔서 덕분에 4주차까지 마무리를 할 수 있었습니다.침대에 누울까 생각을 하다가도 O 표시를 보고 책상앞에 앉았습니다.퇴근 후, 책상 앞에서 공부하는 하나의 루틴을 만든 것 같아 기쁩니다.  

데브옵스 · 인프라

Howon Jeong

[인프런 워밍업 클럽 4기] DevOps 발자국 1주차

 이번 주차는 쿠버네티스의 설치와 각 Object간의 연결에 대한 큰 흐름을 다루는 내용이었다. 사실, 큰 흐름 자체는 이해가 되지만 아직 이 환경을 내가 직접 만들어보라고 한다면 못 할 것 같다. 하지만, 완강 후에는 이 생각 또한 달라져 있을 것이라고 믿는다. 쿠버네티스를 공부하기 전에 Container를 좀 더 편하게 관리하고 이것을 모니터링하며 자동화 할 수 있다는 것은 알고 있었다.하지만, 추상적으로만 알고 있었지 무엇을 어떻게 한다는 것인지는 잘 모르는 상태였다. Docker를 공부할 때는 큰 어려움은 없었기에 쿠버네티스도 비슷한 것이라는 안일함으로 강의에 발을 들였다.하지만, 실상은 생소한 개념들과 무수한 yaml파일, 명령어들이 기다리고 있었다. 그래도 다행인지 큰 개념은 어느 정도 잡힌 것 같다. 쿠버네티스는 Pod라는 작은 단위로 배포를 하며, 이것은 1개 이상의 Container를 담을 수 있다는 것Pod에서 메모리 누수와 같은 문제로 서버가 다운되었을 때, 자동으로 재시작을 해준다는 것 (Self-Healing)Pod의 정의된 CPU 사용량을 초과할 경우 미리 yaml에 정의해둔 기준으로 Pod를 증가/감소 시킬 수 있다는 것 (Auto-Scaling)Rolling Update, Traffic Routing 등도 있지만 생략하겠다. 하지만, 여전히 개념이 잘 잡히지 않는 부분이 있다. Pod란 도대체 무엇인가?쿠버네티스에 배포하는 가장 작은 단위로 Pod를 사용한다는 것은 알겠다. 1개의 Pod에 Container를 여러 개 담을 수 있다는데, 아직까지 Pod를 여러 개 사용하는 상황과 1개의 Pod에서 여러 Container를 사용해 운영하는 환경의 차이를 잘 모르겠다. 이번 한 주는 아직 쿠버네티스에 익숙하지 않던 내가 점점 익숙해지는 과정이라고 생각한다. 그리고 강의를 진행하면서 지식이 부족했던 부분은 아무래도 개인적으로 정리해두고 따로 공부해야 될 부분인 것 같다. 다음 주차는 세부적인 개념에 대한 궁금증은 잠시 다른 곳에 접어두고 큰 그림을 보며 이해하려고 노력해봐야겠다.  

데브옵스 · 인프라

워밍업 클럽 데브옵스 4기 - 발자국 4주차

이번에 Helm, Kustomize,ArgoCD를 공부하면서 쿠버네티스 배포 자동화에 대한 전반적인 흐름을 이해할 수 있었다. 단순히 매니페스트 파일을 작성해서 kubectl apply만 하던 수준에서 벗어나, 어떻게 효율적으로 구성하고 관리하며, 자동으로 릴리즈까지 이어지게 만들 수 있을까에 대해 고민해볼 수 있는 좋은 시간이었다. 우선 Helm과 Kustomize를 비교하면서 각각의 장단점이 뚜렷하다는 걸 느꼈다. Helm은 생태계가 크고 재사용성이 높아서 기업 환경에 적합하다는 걸 알게 되었고, 반면 Kustomize는 단순하고 직관적이라 MVP나 테스트 단계에서는 빠르게 적용할 수 있다는 점이 인상적이었다. 나 같은 초보자 입장에선 Kustomize가 진입 장벽이 낮아 시작하기 좋았지만, 규모가 커질수록 Helm이 필요하겠다는 판단이 들었다. ArgoCD는 지금까지 써봤던 배포 툴 중에 가장 체계적이고, GitOps라는 개념을 잘 이해하는 데 도움이 됐다. 특히 자동 동기화, Rollout 전략 설정, Image 업데이트 자동화 등 하나하나가 실무에 적용 가능한 기능들이라 흥미롭게 공부할 수 있었다. UI도 직관적이라 배포 현황을 한눈에 파악할 수 있는 점도 좋았다. 어려웠던 건 아무래도 Helm의 템플릿 문법이다. Go 텍스트 함수라든지, values.yaml 구조를 처음 볼 땐 복잡하게 느껴졌다. 그리고 Rollout 전략 설정하면서 setWeight, pause, AnalysisTemplate 같은 키워드들을 실제로 어떻게 적용해야 할지 처음엔 좀 막막했다. 하지만 예제를 하나씩 따라해보면서 감을 잡았고, 앞으로 직접 적용해보면서 더 익숙해질 수 있을 것 같다.이번 과정을 통해 단순한 배포 자동화를 넘어서, 안정적이고 반복 가능한 배포 시스템을 설계하는 법에 대해 고민하게 되었고, 이를 나만의 프로젝트에도 적용해보면서 진짜 실력을 쌓고 싶다는 생각이 들었다.

hyunolike

[인프런 워밍업 클럽 4기] DevOps 발자국 4주차

[ 워밍업 클럽 4주차 회고 ]Helm에서 ArgoCD까지, 배포 자동화의 진화 이번 주는 쿠버네티스 패키지 관리와 GitOps의 세계로 본격 진입한 시간이었다. 단순한 kubectl apply에서 벗어나 '지속 가능한 배포'가 무엇인지 체감할 수 있었던 소중한 일주일이었다. Helm과 Kustomize - 패키지 관리의 두 가지 철학18강에서 다룬 Helm과 Kustomize 비교는 정말 인상 깊었다. 같은 목적을 가지고 있지만 접근 방식이 완전히 다른 두 도구를 직접 써보니, 각각의 철학이 확실히 드러났다.Helm은 '차트'라는 패키지 개념으로 재사용성에 집중했고, values.yaml을 통한 환경별 설정 관리가 직관적이었다.Kustomize는 기존 YAML을 건드리지 않고 overlay로 확장하는 방식이 더 쿠버네티스 네이티브하게 느껴졌다.특히 Helm 배포 실습에서 패키지 설치/업그레이드/롤백이 한 줄 명령어로 가능한 부분은 정말 강력했다. 하지만 Kustomize의 심플함도 매력적이었다. 결국 "팀의 상황과 프로젝트의 복잡도에 따라 선택하는 것"이 핵심이라는 걸 깨달았다. ArgoCD와의 첫 만남 - GitOps의 실체19강 ArgoCD 패키지 레벨업은 이번 주 하이라이트였다. 지금까지 배웠던 CI/CD가 'Push' 방식이었다면, ArgoCD는 'Pull' 방식의 GitOps를 보여줬다.Git 저장소의 변경사항을 ArgoCD가 주기적으로 감지해서 클러스터 상태를 동기화하는 과정을 보면서, "배포의 책임을 누가 가져야 하는가"에 대한 새로운 관점을 얻었다. 더 이상 Jenkins에서 클러스터로 직접 배포하는 것이 아니라, Git이 Single Source of Truth가 되는 구조가 훨씬 안전하고 추적 가능하다는 점이 인상적이었다. ArgoCD 아키텍처부터 실전 배포까지ArgoCD 설치부터 Argo Apps 설정, 그리고 실제 배포까지의 전 과정을 따라가면서 GitOps의 전체 흐름을 체험할 수 있었다.Application CRD를 통한 배포 정의자동 동기화 vs 수동 승인Health Status와 Sync Status의 차이점Git 기반 배포 히스토리 추적이런 개념들이 실습을 통해 하나씩 명확해졌다. 특히 ArgoCD UI에서 배포 상태를 시각적으로 확인할 수 있는 부분은 기존 CLI 기반 배포와는 차원이 다른 경험이었다. Image Updater - 자동화의 완성새로운 이미지가 레지스트리에 푸시되면 자동으로 Git 저장소의 매니페스트를 업데이트하고, ArgoCD가 이를 감지해서 배포까지 자동으로 이어지는 완전한 자동화 파이프라인을 구현할 수 있다는 점이 감동적이었다.이제야 "진정한 CI/CD"가 무엇인지 이해했다. 단순히 빌드-테스트-배포를 자동화하는 것을 넘어, Git 커밋부터 프로덕션 배포까지의 전체 흐름이 하나로 연결되는 구조 말이다.Blue/Green과 Canary - 배포 전략의 실제Blue/Green 배포와 Canary 배포를 ArgoCD와 연동해서 구현하는 실습은 이론으로만 알고 있던 배포 전략들을 직접 경험할 수 있는 소중한 시간이었다.특히 Canary 배포에서 트래픽을 점진적으로 증가시키면서 메트릭을 모니터링하고, 문제가 생기면 자동으로 롤백하는 과정을 보면서 "실무에서는 이런 식으로 안전하게 배포하는구나"를 체감했다.실무 관점에서 본 일주일이번 주는 단순한 기술 습득을 넘어 "어떻게 하면 더 안전하고 효율적으로 서비스를 운영할 수 있을까"에 대한 깊은 고민을 하게 된 시간이었다.Helm차트를 직접 작성하고, ArgoCD로 GitOps를 구현하며, 다양한 배포 전략을 실습하는 과정에서 DevOps 엔지니어의 역할이 단순한 '배포 담당자'가 아닌 '서비스 안정성의 설계자'라는 것을 느꼈다. 

4주차 발자국

1. 학습 회고4주차 키워드: Mock과 테스트를 위한 Tipsday16 - Layered Architecture 마지막 강의, [미션] Layered별 특징과 테스트 방법day17 - Mockday18 - 테스트 작성 조언, [미션] 테스트 어노테이션들과 댓글 서비스 테스트day19 - Spring REST Docsday20 - 중간점검 4주차는 테스트와 관련된 어노테이션들과 테스트 코드를 어떤 식으로 구성하면 좋을지에 대해 학습하는 주였다.개인적으로는 헷갈렸던 여러 어노테이션들을 짚고 넘어가는 주여서 좋았다.1달이 생각보다 금방 지나가서 놀랐는데 다음에는 다른 분야의 워밍업클럽도 참여해보고 싶다. 미션 회고Day 16 미션 Presentation, Business, Persistence 3개 Layer의 특징과 어떻게 테스트하면 좋을지 나만의 언어로 표현강의를 기반으로 Layered별 특징을 요약해서 제출했는데,Presentation/Business/Persistence 각 계층을 어떤 식으로 대하면 좋을지,특히, Besiness에서는 LocalDateTime처럼 예상치 못한 결과를 얻을 수 있거나 테스트하기 어려운 코드는 아닌지Presentation에서는 정책에 대한 검증까지 하는 건 아닌지 등 주의해야 할 점들을 다시 한 번 정리하는 미션이었다. Day 18 미션은 테스트에 사용되는 어노테이션들을 정리하고,제시된 코드를 보고 @BeforeEach, given절, when절에 적절히 배치해보는 미션 18-1. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 에 대해서는강의내용을 기반으로 간략히 정리를 했다.다시 한 번 정리를 하면, 테스트의 편의를 위해 Mocking을 하며, 어노테이션들을 사용하면 더 편리하게 다룰 수 있다.XXXBean과의 가장 큰 차이점은 XXXBean은 Spring 환경에서 ApplicationContext에서 Bean 으로 관리되어의존성 처리가 편하다는 점.그 외 Spring 이 필요없거나 의존성이 적고, 간단한 테스트들의 경우 @Mock, @InjectMocks을 활용하면 되겠다. 18-2. 주어진 코드는 writeCommet, updateComment, cannotUpdateCommentWhenUserIsIsNotWriter 3개댓글을 생성/수정 등에 대한 검증이므로 확인하고자 하는 행위들을 when 절에,그 외 나머지 것들은 모두 준비단계이므로 given 절에 배치했다.따라서, writeCommet에는 댓글 생성, updateComment에는 댓글 수정, cannotUpdateCommentWhenUserIsIsNotWriter에는 댓글 수정 시도를 when 절에 배치했다. 이제 @BeforeEach 에 대해 고민해 봐야하는데,@BeforeEach는 테스트 실행 전에 수행되는 단계로 모든 테스트에 영향을 미칠 수 있어 주의해야 한다.지금 수행 중인 테스트는 댓글 서비스 테스트이고, 어떠한 경우든 댓글을 작성하기 위해서는사용자와 게시물 생성이 필수일 것이라 생각했다.그리고 앞으로 댓글에 대한 테스트가 추가된다고 해도 사용자/게시글 생성이 선행되어야 댓글이 있을 것이다.따라서, @BeforeEach 에 사용자 생성에 필요한 내용 준비/생성, 게시물 생성에 필요한 준비/생성을 배치했다. 학습 출처인프런 워밍업 클럽 스터디 4기 - 백엔드 클린코드, 테스트 코드수강 강의:Practical Testing: 실용적인 테스트 가이드 - 박우빈

워밍업 클럽 4기 BE - 4주차 발자국

4주차 미션 회고레이어 아키텍처에서 각 계층별로 테스트 코드를 작성하는 실용적인 방법을 체계적으로 익힐 수 있었다. 특히 Controller, Service, Repository 계층에서 어떤 부분을 중점적으로 테스트해야 하는지, 그리고 각 계층 간의 의존성을 어떻게 효과적으로 격리할 수 있는지에 대한 명확한 가이드라인을 얻었다. 또한 @Mock, @MockBean, @Spy 등 여러 Mock 애노테이션들의 차이점과 사용 시점을 명확히 구분할 수 있게 되면서, 상황에 맞는 적절한 Mock 전략을 선택할 수 있는 능력을 키울 수 있었다. BDD 스타일의 테스트에서는 Given-When-Then 각 단계를 명확히 구분하여 작성할 수 있게 되었다. 4주차 강의 회고테스트 코드를 작성하면서 그동안 애매하게 느꼈던 부분들이 많이 해소되었다. 기본적인 Mock 사용법부터 Spring REST Docs까지 학습하면서 실무에서 바로 적용할 수 있는 실용적인 지식을 쌓을 수 있었고, 테스트 코드에 대한 막연한 두려움도 자연스럽게 사라졌다.길다면 길고 짧다면 짧은 4주라는 시간이 빠르게 지나갔지만, 다행히 강의와 미션들을 무사히 완주했다. 클린코드와 테스트코드는 모든 개발자의 기본 소양이라고 생각하는데, 이번 기회를 통해 그 기반을 탄탄히 다지게 되어 앞으로 더 발전할 수 있는 든든한 토대를 마련한 느낌이다. 4주차 학습 내용 요약테스트 더블테스트를 진행하기 어려운 경우 이를 대신해 테스트를 진행할 수 있도록 만들어주는 객체Mokito 주요 애노테이션✅@InjectMocks 주의사항@InjectMocks은 Mockito 테스트 영역에서 사용되며, @Mock이나 @Spy로 생성된 Mockito 객체만 주입 대상으로 인식한다.따라서 @InjectMocks은 스프링 컨텍스트와는 무관하게 동작하며, @MockBean이나 @SpyBean 같은 스프링 테스트 애노테이션으로 생성된 객체를 주입받을 수 없다.@InjectMocks이 적용된 객체는 필드 주입, 생성자 주입, setter 주입 등을 통해 @Mock 또는 @Spy 객체가 자동으로 주입된다.✅@SpyBean 주의사항@SpyBean은 스프링 컨텍스트에 실제로 등록된 빈을 감싸는 프록시 객체를 생성하여 사용한다.따라서 @SpyBean의 대상이 인터페이스인 경우에는 스프링 컨텍스트에 해당 인터페이스를 구현한 실제 구현체 빈이 반드시 존재해야 한다.BDDMockito// Mockito Mockito.when(mailSendClient.sendEmail(anyString(), anyString(), anyString(), anyString())) .thenReturn(true); // BDDMockito BDDMockito.given(mailSendClient.sendEmail(anyString(), anyString(), anyString(), anyString())) .willReturn(true); BDD 스타일로 Mockito를 사용할 수 있도록 지원해주는 라이브러리이다.실제 Mockito를 상속해서 구현한 객체이므로 모든 기능은 Mockito와 동일하다.더 나은 테스트 작성법✅하나의 테스트에서 하나의 검증만 수행하기(한 문단에 한 주제)for (ProductType productType : productTypes) { if (productType == ProductType.HANDMADE) { ... } if (productType == ProductType.BAKERY) { ... } } void containsStockType() { ProductType givenType = ProductType.HANDMADE; boolean result = ProductType.containsStock(givenType); assertThat(result).isFalse(); } void containsStockType2() { ProductType givenType = ProductType.BAKERY; boolean result = ProductType.containsStock(givenType); assertThat(result).isTrue(); } 분기문, 반복문 등의 논리 구조를 지양해야 한다.DisplayName을 한 문장으로 구성할 수 있는지 판단해보자. ✅제어 가능한 테스트가 가능하도록 코드 작성하기public Order createOrder() { LocalDateTime currentDateTime = LocalDateTime.now(); LocalDate currentDate = currentDateTime.toLocalDate(); if (currentTime.isBefore(...)) throw new IllegalArumentException(...) } public Order createOrder(LocalDateTime currentDateTime) { LocalDate currentDate = currentDateTime.toLocalDate(); if (currentTime.isBefore(...)) throw new IllegalArumentException(...) }  ✅테스트 간 독립성 보장하기@TestInstance(TestInstance.Lifecycle.PER_CLASS) class SharedStateTest { private int count = 0; @Test void testIncrementOnce() { count++; assertThat(count).isEqualTo(1); // ✅ 통과 } @Test void testIncrementTwice() { count++; count++; assertThat(count).isEqualTo(2); // ❌ 실패 (이전 테스트에서 count 증가됨) } } 테스트가 외부 조건, 순서, 공유 상태 등에 영향을 받지 않고 항상 동일한 조건에서 수행되어야 한다. ✅한 눈에 들어오는 Test Fixture@DisplayName("신규 상품을 등록한다. 상품번호는 가장 최근 상품의 상품번호에서 1 증가한 값이다.") @Test void createProduct() { // Given Product product = createProduct("001", HANDMADE, SELLING, "아메리카노", 4000); productRepository.save(product); // When ProductResponse productResponse = productService.createProduct(request); // Then ... } // 픽스처 생성 메서드 // **createProduct 테스트에서 상품번호 외의 값은 고려할 대상이 아니다.** private Product createProduct(String productNumber) { return Product.builder() .productNumber(productNumber) .type(HANDMADE) .sellingStatus(SELLING) .name("아메리카노") .price(4000) .build(); } beforeAll, setUp (@beforeEach) 사용 지양하기 (사용하고 싶다면 아래 2가지 질문해보기) 각 테스트 입장에서 봤을 때, 아예 몰라도 테스트 내용을 이해하는 데에 문제가 없는가?수정해도 모든 테스트에 영향을 주지 않는가?data.sql과 같은 공통 로직으로 테스트 픽스처 구성하지 않기픽스처 생성 로직은 같은 테스트 클래스에서 관리하기픽스처 생성 메서드에서는 정말 필요한 값만 파라미터로 받기 테스트는 하나의 이해하기 쉬운 문서처럼 작성되어야 하며, given 절에서 테스트의 픽스처를 구성하는 것이 가독성과 유지보수 측면에서 유리하다. ✅Spring Data JPA 사용 환경에서 Test Fixture 클렌징 시 주의사항✅@DaynamicTestclass OrderStatusDynamicTest { @TestFactory Collection<DynamicTest> testOrderStatusTransitionsWithDifferentLogic() { return List.of( DynamicTest.dynamicTest("CREATED → PAID: 결제 처리 및 영수증 생성", () -> { // Given Order order = new Order(OrderStatus.CREATED); // When order.processPayment(); // 내부에서 status 변경 + 영수증 생성 // Then assertEquals(OrderStatus.PAID, order.getStatus()); assertNotNull(order.getReceipt()); }), DynamicTest.dynamicTest("PAID → SHIPPED: 송장 발급 및 상태 변경", () -> { // Given Order order = new Order(OrderStatus.PAID); // When order.prepareShipment(); // 송장 생성 + 상태 변경 // Then assertEquals(OrderStatus.SHIPPED, order.getStatus()); assertNotNull(order.getInvoiceNumber()); }), DynamicTest.dynamicTest("SHIPPED → DELIVERED: 배송 완료 처리", () -> { // Given Order order = new Order(OrderStatus.SHIPPED); // When order.markAsDelivered(); // Then assertEquals(OrderStatus.DELIVERED, order.getStatus()); assertTrue(order.isDeliveredTimeRecorded()); }) ); } } 전체 테스트 수행 시간 줄이기✅스프링 컨텍스트가 다시 로딩되는 케이스스프링 테스트 프레임워크는 컨텍스트 로딩 비용을 줄이기 위해 컨텍스트 캐시를 사용한다.동일한 설정(Class, 프로파일, MockBean 등)이면 컨텍스트를 재사용한다.하지만 위와 같은 조건이 달라지면 캐시가 무효화되고 컨텍스트 재로딩이 발생한다. ✅해결 방법Spring REST Docs테스트 코드를 통한 API 문서 자동화 도구이다.API 명세를 문서로 만들고 외부에 제공함으로써 협업을 원활하게 한다.기본적으로 AsciiDoc을 사용하여 문서를 작성한다.테스트 코드를 통과해야 문서가 만들어진다.프로덕션 코드에 비침투적이다. (Swagger는 침투적이다.) ✅빌드 설정 plugins { id "org.asciidoctor.jvm.convert" version "3.3.2" } configurations { asciidoctorExt } dependencies { asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor:{project-version}' (3) testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc:{project-version}' (4) } // 테스트 실행 시 생성되는 REST Docs 스니펫 파일들이 저장될 디렉토리를 정의 ext { snippetsDir = file('build/generated-snippets') } // 테스트 태스크가 snippetsDir에 출력 파일을 생성한다고 Gradle에 알림 test { outputs.dir snippetsDir } asciidoctor { // 스니펫 파일들을 입력으로 사용 inputs.dir snippetsDir // AsciiDoc 확장 기능 활성화 configurations 'asciidoctorExt' // 모든 하위 폴더의 index.adoc 파일만 처리 sources { include("**/index.adoc") } // 소스 파일의 위치를 기준으로 상대 경로 해석 baseDirFollowsSourceDir() // AsciiDoc 생성 전에 반드시 테스트 실행 dependsOn test } // Spring Boot JAR 파일에 생성된 문서를 포함 bootJar { dependsOn asciidoctor // 생성된 HTML 문서 파일들(현재 예시에서는 index.adoc)을 가져옴 from ("${asciidoctor.outputDir}") { into 'static/docs' } } test → 스니펫 파일 생성 (build/generated-snippets)asciidoctor → AsciiDoc을 HTML로 변환bootJar → 생성된 HTML을 JAR에 포함 ✅스니펫 조합 템플릿 작성ifndef::snippets[] :snippets: ../../build/generated-snippets endif::[] = CafeKiosk REST API 문서 :doctype: book :icons: font :source-highlighter: highlightjs :toc: left :toclevels: 2 :sectlinks: [[Product-API]] == Product API // 유지보수 편의를 위해 각각의 adoc 파일을 분리하여 index.adoc 파일에 합칠 수 있다. include::api/product/product.adoc[]기본 경로 : src/docs/asciidoc/index.adocgenerated-snippets에 생성된 코드 조각들을 하나의 완성된 문서로 조합하는 템플릿 역할을 한다.AsciiDoctor는 index.adoc을 처리하여 완성된 HTML 문서를 생성한다.여러 스니펫(파일 조각)을 어떤 형식으로 배치할지 결정한다. ✅커스텀 스니펫 템플릿 작성src/test/resources/org/springframework/restdocs/templates/asciidoctor/ ├── request-fields.snippet ├── response-fields.snippet ├── path-parameters.snippet ├── request-parameters.snippet ├── http-request.snippet ├── http-response.snippet ├── curl-request.snippet └── ...기본 경로 : src/test/resources/org/springframework/restdocs/templates/asciidoctor/==== Request Fields |=== |Path|Type|Optional|Description {{#fields}} |{{#tableCellContent}}`+{{path}}+`{{/tableCellContent}} |{{#tableCellContent}}`+{{type}}+`{{/tableCellContent}} |{{#tableCellContent}}{{#optional}}O{{/optional}}{{/tableCellContent}} |{{#tableCellContent}}{{description}}{{/tableCellContent}} {{/fields}} |===request-fields.snippet 오바라이드 예시Spring REST Docs는 기본 스니펫 템플릿이 내장되어 있다.기본 경로에 파일을 생성하면 기본 스니펫 템플릿을 오버라이드할 수 있다.각각의 스니펫을 어떤 형식으로 보여줄지 결정한다. ✅사용 예시 mockMvc.perform(post("/api/v1/products/new") .content(objectMapper.writeValueAsString(request)) .contentType(MediaType.APPLICATION_JSON) ) .andDo(print()) .andExpect(status().isOk()) // restdoc config .andDo(document("product-create", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), // request requestFields( fieldWithPath("type").type(JsonFieldType.STRING).description("상품 타입"), fieldWithPath("sellingStatus").type(JsonFieldType.STRING).description("상품 판매상태").optional(), fieldWithPath("name").type(JsonFieldType.STRING).description("상품 이름"), fieldWithPath("price").type(JsonFieldType.NUMBER).description("상품 가격") ), // response responseFields( fieldWithPath("code").type(JsonFieldType.NUMBER).description("코드"), fieldWithPath("status").type(JsonFieldType.STRING).description("상태"), fieldWithPath("message").type(JsonFieldType.STRING).description("메시지"), fieldWithPath("data").type(JsonFieldType.OBJECT).description("응답 데이터"), fieldWithPath("data.id").type(JsonFieldType.NUMBER).description("상품 ID"), fieldWithPath("data.productNumber").type(JsonFieldType.STRING).description("상품 번호"), fieldWithPath("data.type").type(JsonFieldType.STRING).description("상품 타입"), fieldWithPath("data.sellingStatus").type(JsonFieldType.STRING).description("상품 판매상태"), fieldWithPath("data.name").type(JsonFieldType.STRING).description("상품 이름"), fieldWithPath("data.price").type(JsonFieldType.NUMBER).description("상품 가격") ) ) );requestResponse

dohi

워밍업 클럽 4기 - 백엔드 Day 18

과제 Day181. Mockito 주요 어노테이션 정리 (@Mock, @MockBean, @Spy, @SpyBean, @InjectMocks)@Mock순수 Mockito 기반 Mock 객체 생성. 실제 동작 없이 필요한 부분만 Stubbing 가능. Spring Context와 무관@MockBeanSpring Context에 등록되는 Mock 객체.기존 Bean을 대체함. @SpringBootTest, @WebMvcTest 등에서 사용.@Spy실제 객체를 감싸서 일부만 Stubbing 가능. 상태 확인이나 부분 동작 제어 시 유용. Mockito 단독 사용 가능.@SpyBeanSpring Context에 등록된 Bean을 Spy로 교체.실제 동작은 유지하면서 일부만 Stubbing.@InjectMocks@Mock 또는 @Spy 객체를 테스트 대상 클래스에 주입. 직접 객체 생성 없이 의존성 자동 주입을 지원.요약 Spring 없이 단순 로직 테스트: @Mock, @InjectMocks, @SpySpring 환경 테스트: @MockBean, @SpyBean실제 동작을 살리되 일부만 조작하고 싶을 때: @Spy, @SpyBean전체를 가짜 객체로 대체할 때: @Mock, @MockBean2. 테스트의 각 항목을 @BeforeEach, given절, when절에 배치AS-IS@BeforeEach void setUp() { ❓ } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { 1-1. 사용자 생성에 필요한 내용 준비 1-2. 사용자 생성 1-3. 게시물 생성에 필요한 내용 준비 1-4. 게시물 생성 1-5. 댓글 생성에 필요한 내용 준비 1-6. 댓글 생성 // given ❓ // when ❓ // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { 2-1. 사용자 생성에 필요한 내용 준비 2-2. 사용자 생성 2-3. 게시물 생성에 필요한 내용 준비 2-4. 게시물 생성 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 2-7. 댓글 수정 // given ❓ // when ❓ // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { 3-1. 사용자1 생성에 필요한 내용 준비 3-2. 사용자1 생성 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-5. 사용자1의 게시물 생성에 필요한 내용 준비 3-6. 사용자1의 게시물 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 3-9. 사용자2가 사용자1의 댓글 수정 시도 // given ❓ // when ❓ // then 검증 } TO-BE@BeforeEach void setUp() { 0-1. 사용자 생성에 필요한 내용 준비 (1-1, 2-1, 3-1) 0-2. 사용자 생성 (1-2, 2-2, 3-2) 0-3. 게시물 생성에 필요한 내용 준비 (1-3, 2-3, 3-5) 0-4. 게시물 생성 (1-4, 2-4, 3-6) } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given 1-5. 댓글 생성에 필요한 내용 준비 // when 1-6. 댓글 생성 // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { // given 2-1. 댓글 생성에 필요한 내용 준비 (2-5) 2-2. 댓글 생성 (2-6) // when 2-3. 댓글 수정 (2-7) // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-1. 사용자2 생성에 필요한 내용 준비(3-3) 3-2. 사용자2 생성(3-4) 3-3. 사용자1의 댓글 생성에 필요한 내용 준비(3-7) 3-4. 사용자1의 댓글 생성(3-8) // when 3-5. 사용자2가 사용자1의 댓글 수정 시도 (3-9) // then 검증 }작업.공통으로 사용하는 게시판과 사용자(1)은 Setup댓글도 공통으로 사용한다라고 볼 수 있지만 writeComment의 테스트에서 When에 해당하여 제외그외 when에 기준으로 필요한 데이터 생성은 given에 배치

백엔드워밍업클럽4기워밍업클럽백엔드

dohi

워밍업 클럽 4기 - 백엔드 Day 4

수정내역썸네일 추가과제1. 읽기 좋은 코드로 리팩토링해 보기AS-ISpublic boolean validateOrder(Order order) { if (order.getItems().size() == 0) { log.info("주문 항목이 없습니다."); return false; } else { if (order.getTotalPrice() > 0) { if (!order.hasCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } else { return true; } } else if (!(order.getTotalPrice() > 0)) { log.info("올바르지 않은 총 가격입니다."); return false; } } return true; }  TO-BEEarly Return 적용if else 문에 대한 조건에 대하여 if문 별 return이 존재하다는걸 파악하였고 조건에 맞게 Early Return적용 order가 null일 경우 추가 적용공백 라인 적용if문에 대한 공백 라인을 적용함으로서 코드의 분기점을 명확하게 구분부정연산자를 메서드안에 포함하여 메서드명으로 확인할 수 있도록 변경!(order.getTotalPrice() > 0), !order.hasCustomerInfo() 의 가독성 향상을 위한 메서드화 예외 처리return false; 에 대해서 각 메서드에서 IllegalArgumentException 예외를 던지도록 수정하였고예외처리를 통해 log를 try-catch문으로 한번에 처리하도록 수정(1번버전) 1. 예외처리 버전 ( 다소 엄격 )public boolean validateOrder(Order order) { if (order == null) { log.info("Order 객체가 null입니다."); return false; } try{ validateOrderItemsExist(order); validateTotalPrice(order); validateCustomerInfoPresent(order); return true; }catch(IllegalArgumentException e) { log.info(e.getMessage()); return false; } } public void validateOrderItemsExist(Order order) { if (order.getItems().size() == 0) { //order.getItems().isEmpty()도 고려 throw new IllegalArgumentException("주문 항목이 없습니다."); } } public void validateTotalPrice(Order order){ if((order.getTotalPrice() <= 0)){ throw new IllegalArgumentException("올바르지 않은 총 가격입니다."); } } public void validateCustomerInfoPresent(Order order) { if (!order.hasCustomerInfo()) { throw new IllegalArgumentException("주문에 사용자 정보가 필요합니다."); } } 2. 예외처리 미적용public boolean validateOrder(Order order) { if (isOrderNull(order)) return false; if (isOrderItemsEmpty(order)) return false; if (isTotalPriceInvalid(order)) return false; if (isCustomerInfoMissing(order)) return false; return true; } public boolean isOrderNull(Order order) { if (order == null) { log.info("Order 객체가 null입니다."); return true; } return false; } public boolean isOrderItemsEmpty(Order order) { if (order.getItems().size() == 0) { //order.getItems().isEmpty()도 고려 log.info("주문 항목이 없습니다."); return true; } return false; } public boolean isTotalPriceInvalid(Order order) { if((order.getTotalPrice() <= 0)){ log.info("올바르지 않은 총 가격입니다."); return true; } return false; } public boolean isCustomerInfoMissing(Order order) { if (!order.hasCustomerInfo()) { log.info("사용자 정보가 없습니다."); return true; } return false; }  2. SOLID에 대하여 자기만의 언어로 정리해 봅시다. 1.  SRP - Single Responsibility Principle(단일 책임 원칙)한 클래스는 딱 하나의 역할만 하자.하나의 클래스가 너무 많은 일을 하려고 하지 말자.  2.  OCP- Open/Closed Principle(개방/폐쇄 원칙)기존 코드를 고치지 않고, 기능을 확장할 수 있어야 한다.수정에는 닫혀 있고, 확장에는 열려 있어야 한다.조건문을 늘리기보다는 새로운 클래스를 추가해 기능을 확장하자. 3.  LSP - Liskov Substitution Principle(리스코프 치환 원칙)부모 타입을 사용하는 곳에 자식 타입을 써도 제대로 작동해야 한다.부모 클래스의 역할을 자식이 완전히 대체할 수 있어야 한다.자식 클래스가 부모의 약속을 깨면 안 된다.  4. ISP - Interface Segregation Principle(인터페이스 분리 원칙)쓸데없는 인터페이스는 나눠서 큰 종합세트를 주지말고 작은 인터페이스 여러개가 좋다클라이언트가 사용하지 않는 메서드에 의존하게 하지 말자.하나의 거대한 인터페이스보다는, 작은 인터페이스 여러 개가 좋다.  5. DIP - Dependency Inversion Principle(의존 역전 원칙)고수준 모듈은 저수준 모듈에 의존하지 말고, 추상(인터페이스)에 의존하자.핵심 로직(고수준)이 세부 구현(저수준)에 끌려다니면 유연성이 떨어진다.인터페이스를 사이에 두고 서로 느슨하게 연결하자.   강의Readable Code: 읽기 좋은 코드를 작성하는 사고법

백엔드백엔드워밍업클럽4기워밍업클럽

dohi

워밍업 클럽 4기 - 백엔드 Day 16

수정내역썸네일 추가과제1. Persistence Layer데이터를 읽고 쓰는 기능, 즉 DB와 직접 연결되는 창구 역할을 합니다.데이터 저장, 조회, 수정, 삭제 같은 순수한 CRUD 작업만 담당해야 하며, 복잡한 계산이나 로직은 포함되면 안 됩니다.어떻게 테스트?JPA 기반의 Repository를 중심으로 테스트합니다.@ActiveProfiles를 사용해 테스트 전용 DB를 따로 두어 테스트실제 데이터를 저장하고 불러오면서 동작을 검증합니다.예: 특정 조건으로 조회 시 원하는 값이 정확히 나오는지 확인 @DataJpaTest 사용시 자동으로 롤백 (@Transactional)포인트빠르게 테스트하고 싶으면 @DataJpaTest순수하게 CRUD에 집중해야 하므로, 로직이 들어있다면 오히려 잘못된 구조일 수 있음2. Business Layer비즈니스 로직을 담는 곳입니다.예를 들어 “결제를 하면 재고가 줄어야 한다” 같은 업무 흐름을 구현하는 레이어며트랜잭션 보장과 동시성을 고민해야한다.어떻게 테스트?@SpringBootTest 또는 @ServiceTest 등으로 전체 흐름을 확인할 수 있는 환경 구성필요한 데이터는 테스트 전 직접 저장하거나 Mock 처리경계값 테스트given-when-then 구조로 시나리오 기반 테스트 작성포인트이 레이어는 트랜잭션이 중요한 레이어이므로, 롤백 여부도 테스트 대상핵심은 “이 비즈니스 흐름이 내가 기대한 대로 잘 작동하느냐”임3. Presentation Layer웹 요청(HTTP 등)을 처음으로 받아들이는 입구입니다.컨트롤러에서 파라미터를 검증하고, 서비스에 요청을 위임하며, 응답을 구성합니다.즉, 입력과 출력의 인터페이스 역할을 합니다.어떻게 테스트?단위 테스트처럼 접근컨트롤러만 띄우고, 내부 서비스나 레포지토리는 Mock 처리MockMvc, @WebMvcTest 등을 이용해 REST API 요청/응답을 검증validation, 상태 코드, JSON 응답 구조를 확인포인트복잡한 로직보다 “입력값에 따라 어떤 응답이 나오는가”에 집중실제 호출 흐름이 아니라 API 인터페이스가 잘 동작하는지만 보자과제 회고각 레이어마다 역할이 다르기 때문에,그에 맞는 테스트 전략과 도구도 달라져야 한다는 걸 이번에 확실히 느꼈습니다.Persistence는 DB를 잘 다루는지Business는 로직 흐름이 맞는지Presentation은 입력과 출력이 잘 연결되는지

워밍업클럽워밍업클럽4기백엔드

양파쿵야

워밍업클럽4기 DevOps 4주차 발자국

Helm과 Kustomize 비교하며 사용-2Helm과 Kustomize는 무엇이 더 좋다기보단, 서로 지향하는 방향이 극명히 다른 것 같다. 대규모 배포를 사용하게 될지 아직은 잘 모르겠어서... 약간은 더 직관적으로 느껴지는 Kustomizee부터 사용하게 될 것 같다.최근 보안과 관련해 안좋은 소식들이 많이 있었기에, 도커 허브와 쿠버네티스 클러스터에 대한 접근 제어를 강화하는 방법을 실습할 수 있어서 좋았다.컴퓨터가 좋지 않아 빌드를 계속한다.... 10분이 넘어도 멈추지 않는다.... ArgoCD 빠르게 레벨업-1ArgoCD가 Git을 필요로 하는 만큼, 불필요한 업데이트가 발생하지 않도록 Git 레포지토리를 분리해서 관리하는게 정말 중요할 것 같다.Jenkins Pipeline과 비교해 배포가 간단하고, 무엇보다 쿠버네티스와 동기화되어 배포 상태를 그래픽으로 한번에 조회할 수 있어서 좋다.로그도 Jenkins는 각 파이프마다 클릭해서 페이지가 이동되고 봐야했는데, ArgoCD는 실시간으로 Pod 로그도 볼 수 있어서 매우 편리했다. ArgoCD 빠르게 레벨업-2ArgoCD Image Update를 사용해야하는 이유를 처음에 이해하지 못했는데 3번 구간 반복하니 이해가 되었다.Git과 완전히 동일한 환경을 구현하고자 할 때 도움되는 옵션도 알게되어, 테스트 환경을 만들 때 유용하게 사용할 수 있을 것 같다.다만... 컨테이너 빌드를 완료했는데 감지하는데 실패했다...(컴퓨터가 너무 느림) - 그치만 미션에선 이미지 변경 감지 성공! ArgoCD 빠르게 레벨업-3CLI를 사용해 모니터링할 수 있다니 ArgoCD는 정말 완벽한 것 같아요YAML 파일의 구성도 기존 쿠버네티스 환경과 호환되도록 세심하게 배려한 게 정말 잘 만든 솔루션이라고 느낍니다Jenkins를 사용해서 Blue/Green과 Canary 배포를 진행할 때는 이론은 쉽지만 막상 스크립도 구현하는 것은 까다로운 배포 작업이라고 생각된 것에 반해, ArgoCD는 정말 딸깍으로 배포할 수 있는 강력한 솔류션 같습니다.

데브옵스 · 인프라워밍업클럽4기

양파쿵야

쿠버네티스 어나더 클래스 지상편: Sprint2 Day17 ArgoCD 3

Argo RolloutsArgoCD 없이도 Rollouts(Blue/Green, Canary) 배포가 가능하다.ArgoCD와 독립적인 솔루션이며, ArgoCD와 함께 사용하면 ArgoCD 대시보드에서 Rollouts 버튼이 생긴다. Blue/Green 배포운영 환경에서만 테스트가 가능한 환경에서 주로 사용하는 배포 전략이다.배포 시 롤백이 빠르다.배포 중 V1 과 V2 간의 동시 호출이 발생하지 않는다.Script를 사용해 자동 배포가 가능하다.V2에 과도한 트래픽이 유입될 경우 문제가 발생할 수 있다. Rollouts을 사용한 Blue/Green 배포 과정Rollout 컨테이너 → Service 2개 지정: Active(서비스 사용자 접근), Preview(V2로만 접근) V1(Blue) 배포Rollout → Replica Set V1 → Pod V1 ← Active / Preview Service배포 이전에는 2개 서비스 모두 Blue를 바라본다 V2(Green) 배포Rollout → Replica Set V1 → Pod V1 ← Active ServiceRollout → Replica Set V2 → Pod V2 ←Preview Service ← QA담당자배포 이후에 Preview Service만 Green을 바라본다. PromotePod V1 삭제 ← Promote → Active / Preview Service → Pod V2Promote를 진행하면 Blue는 제거한다 Canary 배포특정 헤더 값에 한해 트래픽이 유입되도록 할 수 있다.서서히 트래픽을 전환하므로 콜드 스타트를 방지할 수 있다.업그레이드 목적 이외에도 두 버전을 비교하기 위한 A/B 테스트에도 사용된다. Rollouts을 사용한 Canary 배포 과정Blue/Green처럼 새 서비스를 만들지 않아도 트래픽을 조절할 수 있다. V1 배포Rollout → Replica Set V1 → Pod V1 ← Service V2(Canary) 배포Rollout → Replica Set V1 → Pod V1 ← ServiceRollout → Replica Set V2 → Canary Pod ← Service Promote순차적으로 Cananry Pod의 비중을 늘림setWeight: 전체 Pod에서 Canary가 차지하는 비중pause: {} : Promote가 올 때까지 무한정 대기 5. Argo Rollouts를 이용한 Blue-Green 배포 - 22335-2. App 생성 하기 - [+ NEW APP] 클릭5-3. 배포하기 - [SYNC] 클릭 > [SYNCHRONIZE] 클릭5-4. 배포 확인배포 완료 5-5. 트래픽 보내기 5-6. ArgoCD UI에서 Blue/Green 배포 시작하기rollout.yaml spec: replicas: 2 strategy: blueGreen: activeService: api-tester-2233-active previewService: api-tester-2233-preview autoPromotionEnabled: falseRollout을 사용하기 위해 배워야할 부분은 spec - strategy - blueGreen 뿐 autoPromotionEnabled: falsetrue일 경우 Green 파드가 정상 작동하면 Promote가 자동으로 반영된다. 5-6-3. Git에서 image의 tag 변경5-6-4. ArgoCD에서 Applications > api-tester-2233 > [SYNC] 클릭Git의 수정 사항을 감지함 5-6-5. 트래픽 확인rollouts-pod-template-hash 를 사용해 트래픽을 전환할 수 있다. 5-6-6. Promote 진행Rollout 대시보드는 기본적으로 안만들어짐Rollback: Green 파드 삭제Restart: Blue/Green 파드 모두 재시작, 원하는 파드를 K8s에서 삭제하여 재시작하는 방법이 더 좋음Promote: 다음 단계PromoteFull: 배포 완료 Promote를 진행한다. 5-6-7. 트래픽 확인 5-7. Rollout CLI로 조회 해보기배포 상황을 모니터링해줌 6. Argo Rollouts를 이용한 Carary 배포 - 22346-1. Master에서 Kubectl로 Rollouts 배포하기 6-2. 배포 모니터링6-3. 트래픽 보내기 (1.0.0 App 연결) 6-5. Argo Rollouts CLI로 Canary 배포 시작하기 (1.0.0 -> 2.0.0로 변경)Canary Pod가 만들어졌다. 6-7. 트래픽 확인 (1.0.0 App 연결, 2.0.0 App 연결)트래픽이 Canary로 분산되고 있다. Promote를 진행해 다음 단계로 넘어간다. 전체 Pod중 66%의 Canary Pod가 생성되었다. 6-8. 트래픽 확인 (2.0.0 App 연결) 배포가 모두 완료되었다!  6-9. 리소스 정리하기     

데브옵스 · 인프라워밍업클럽4기

[워밍업 클럽 4기 백엔드] 3주차 발자국

학습 내용persistence layer 테스트persistence layerdata access 의 역할비즈니스 가공 로직이 포함되어서는 안된다. 데이터에 대한 CRUD에만 집중한 레이어 미래에 어떠한 변경이 될수도 있고 내가 작성한 코드를 확인하기 위해 테스트를 해야한다 Repository test통합 테스트이지만 해당 레이어만 띄워서 하기 때문에 단위 테스트 느낌이 난다 스프링 통합테스트를 위한 어노테이션@springBootTest, @DataJpaTest차이dataJpaTest : jpa 관련 빈 주입해서 서버를 띄워 빠르다assertThat(product).hasSize(2) - 사이즈 확인 .extrating("productNumber", "name" , "sellingStatus") - 검증하고 싶은 셀만 확인 가능 .containsExactlyInAnyOrder( -- 순서 상관없이 해당 것이 포함하는지 확인 tuple("001", "아메리카노", selling), tuple("002", "카페라떼", HOLD) ) business layer 테스트비즈니스 로직을 구현하는 역할Persistence Layer와의 상호작용을 통해 비즈니스 로직을 전개시킨다트랜잭션을 보장해야 한다service 테스트asserThat(orderResponse.getId).isNotNull(); -- null 이 아니다 @springBootTest, @DataJpaTest차이DataJpaTest 는 트랜잭션 어노테이션 있어 사용하면 자동으로 롤백이 된다 presentation layer 테스트 presentation layer외부 세계의 요청을 가장 먼저 받는 계층파라미터에 대한 최소한의 검증을 수행한다 persenation layer 테스트시 해당 부분은 단위테스트 하는 느낌으로 하고 나머지 layer는 mocking 처리를 하여 테스트를 한다 @transactional(readOnly = true)CRUD에서 CUD 동작 X, only read 만 가능jpa : cud 스냅샷 저장, 변경 감지 x (성능 향상)서비스 테스트를 할때 전체 클래스에 @transactional(readOnly = true) 를 걸고 각 command 작업을 하는 메서드에는 @transactional 따로 걸자  느낀점실제 단위 테스트 하면서 어떤 것을 테스트를 해야할지 모르겠다는 느낌을 받았지만 강의를 들으면서 이러한 주제로 나눠서 테스트 해야겠다고 생각을 해볼수 있는 기회가 된거 같다 

백엔드

[워밍업 클럽 4기 - 백엔드] 3주차 발자국

강의 수강 소감Practical Testing: 실용적인 테스트 가이드각 레이어별로 통합테스트방법을 알 수 있다.프레젠테이션 레이어은 MockMvc로 응답, 결과값을 검증한다.비즈니스 레이어의 경우 given 절에 데이터 삽입, when 절에 검증할 비즈니스 레이어의 함수를 사용하고 then 절에서 결과값을 검증한다.영속 레이어의 경우 DataJpaTest 혹은 프레젠테이션레이어처럼 SpringbootTest를 사용한다.다른 영속 인프라와의 통합테스트가 있을 경우를 대비해 SpringbootTest를 사용하는 것을 권장빈 구성이 다르므로 SpringbootTest와 별도로 한번더 띄워지기 때문에 주의과제 회고과정지뢰찾기의 각 클래스의 역할을 재정의했다.TDD를 적용해보기 위해 강의에서 정의해준 역할이 아니라 의문이 들었던 내용에 대해 재분배했다.지뢰가 주변 지뢰를 알고 있는 것이 맞는가 -> Board에 해당 역할 할당.8칸 고정 수에 대한 연산이므로 O(1)이기 때문에 이를 아끼기 위해 선배정하는 것은 과한 최적화라고 생각했음.인수분해하듯이 지뢰 셀과 일반 셀의 같은 구현을 가진 역할을 생각했다. 열고난 후에는 출력시 값을 보여주는 것열지않은 셀에 깃발을 꽂고 회수할 수 있는 것추상화된 역할은 있으나 다르게 구현해야하는 것은 리스코프 치환원칙을 준수해 구현했다.클리어 조건열렸을 때 주변 셀도 열어야하는지 여부지뢰인지 여부toString 메소드가 문자열로 전환하는 역할을 가졌다고 생각해 display와 같은 별도 함수를 사용하지 않았다. 반성강의에서 언급된 리팩토링 테크닉을 최대한 활용하지 않았다.인터페이스에 의존하게 하는 것 합성과 구현관계가 아닌 추상 클래스를 활용해 부모클래스를 알아야하도록 한 것toString으로 인해 도메인 클래스가 단일책임을 지키지 못하는 것처럼 보였다.가로열 수를 알고 있는 Config이 가로열 수를 캡슐화하면 좋겠다는 생각으로 Config에 해당 문자열을 구하는 기능을 배정했으나 클래스의 단일 책임 원칙을 어기도록하는 과도한 캡슐화라고 생각된다.toString으로 getter를 캡슐화한 것도 마찬가지 3주차 회고요구사항을 먼저 정하고 테스트를 작성한 후 작업하다보니, 리팩토링이 아니라 새로 구현하는 느낌을 받았다. 도중에 역할을 몇번 재분배하여 테스트 코드도 많이 변경되었지만 내가 직접 산출한 요구사항을 지키는 코드를 작성하다보니 재미있었다.

wnsrlf0721

[워밍업 클럽:쿠버네티스] 미션#5. 컨테이너 이미지 사례 실습

해당 실습과정은 큐브옵스 카페의 미션을 실습한 과정입니다. Docker와 Containerd 명령 실습https://cafe.naver.com/f-e/cafes/30725715/articles/137 도커 (Docker)CI/CD 환경이 구축된 서버에서 진행▶ 사전 준비사항# 도커 파일 및 App 소스 다운로드 curl -O https://raw.githubusercontent.com/k8s-1pro/install/main/ground/etc/docker/Dockerfile curl -O https://raw.githubusercontent.com/k8s-1pro/install/main/ground/etc/docker/hello.js curl 명령어로 Dockerfile과 hello.js를 CI/CD 서버에 다운받았다. <실습 시작>​1. 빌드2. 이미지 리스트 조회docker image로 hello가 있는걸 확인 3. 태그 변경태크가 다른 이미지가 하나 더 생겼다. 4-1&2. 로그인 및 이미지 업로드Docker Hub를 확인하면 새로만든 hello image가 hub저장소에 있는 걸 확인 5. 이미지 삭제hello 이미지 1.0과 2.0 이 모두 CI/CD 서버에서 제거 된걸 확인 6. 이미지 다운로드Docker Hub에 저장된 hello 이미지를 서버로 다운로드함새로 1.0 hello가 생긴 걸 확인 7. 이미지 -> 파일로 변환hello 이미지를 file.tar로 변환하여 저장▶ 이미지 삭제8. 파일 -> 이미지로 변환file.tar 파일에 저장된 정보를 바탕으로 image load -> hello image 생성확인▶ 정리컨테이너디 (Containerd)쿠버네티스가 있는 인프라 환경에서 진행 <실습 시작>​1. 네임스페이스 조회2. 특정 네임스페이스 내 이미지 조회3. 다운로드 및 이미지 확인 (이미지는 default라는 네임스페이스에 다운 받아집니다.)default 네임스페이스가 생성되어졌고,default 에 hello image 생성을 확인 4. 태그 변경태그를 변경한 결과,이미지 1.0과 2.0이 존재하는 걸 확인 5. 업로드도커허브 상에 2.0 tag가 올라간걸 확인 6. 이미지 (namespace : default) -> 파일로 변환hello:1.0.0이 file.tar로 변환된걸 확인 7. 파일 -> 이미지로 변환 (namespace : k8s.io)k8s.io 네임스페이스에 file.tar 파일을 이미지로 변환해 저장한다.저장 결과 k8s.io 에 hello 이미지가 생성된걸 확인 8. 삭제 (namespace : k8s.io)같은 이미지를 도커에서 받았을 때와 쿠버네티스에서 받았을 때 사이즈가 다른 이유https://cafe.naver.com/f-e/cafes/30725715/articles/158 ▶ Docker Hub (248.26 MB)Docker Hub의 1pro/api-tester 이미지 중 latest tag를 다운받고 비교할 예정이다. ▶ Docker (490MB)▶ Containerd (248.3 MiB) 가정 1. Container Image를 만들 때 플랫폼(amd64, arm64)을 고려해야 되는데, Docker에서는 amd64를 받았고, Kuberentes에서 arm64를 받아서 이미지 크기가 달라졌을 것이다. ▶ Docker (amd64가 보임)▶ Containerd (amd64, arm64)가 보임containerd는 amd64와 arm64 두 버전을 모두 지원하는 이미지임에도 불구하고,amd64 한 버전만 지원하는 Docker의 이미지보다 크기가 작다.따라서 amd64이건 arm64이건 플랫폼에 따라 크기가 달라지는 건 아닌것 같다. 가정 2. Container 이미지는 각각의 Layer로 구성돼 있는데, Docker에서 다운 받을 때는 전체 Layer를 받았고, Kubernetes에는 기존 이미지에 이미 존재하는 Layer가 있기 때문에 새로 받은 이미지의 Size가 작게 조회 됐을 것이다. 위 가정이 맞는 지 확인을 위해 전 가정에서 설치했던 Docker image -> Containerd 옮겨보고,Containerd image -> Docker 환경으로 옮겨보며 사이즈가 어떻게 바뀌나 확인해보겠습니다.▶ Docker -> ContainerdIMG -> 파일로 변환1pro/api-tester image 를 파일로 변환시킨 후 (docker-image.tar 생성)[root@cicd-server ~]# docker save -o docker-image.tar 1pro/api-tester:latest크기를 확인해보니 490MB -> 472MB 로 조금 줄어들었다.파일 복사 (CI/CD -> k8s 서버로)아래와 같이 파일을 인프라 환경에 복사시키고, k8s-master 서버에서 결과를 확인해보겠습니다.정상적으로 잘 받아온 걸 확인했고, 이제 이미지로 변환해서 자료 크기를 확인해야겠죠?파일 -> IMG 변환기존에 존재했던 이미지를 삭제시킨 후, 복사한 파일을 image로 변환시킵니다.이후 k8s 상 동작하는 image 사이즈를 확인하니, 472MB -> 248.3MiB로 바뀌었습니다.▶ Containerd -> DockerIMG -> 파일로 변환k8s 상 존재하는 이미지는 Docker에서 가져온 파일을 통해 만든 것이므로, Docker Hub에서 pull로 이미지를 다시 다운받음.이 이미지를 이제 파일로 변환하면 되겠죠?IMG (248.3MiB) -> 파일 (249M) 변환 완료파일 복사 (CI/CD -> k8s 서버로)CI/CD 환경 상에 잘 복사가 된걸 확인파일 -> IMG 변환기존 이미지 삭제 후 containerd에서 가져온 파일을 img로 변환사이즈 확인 (490MB) 가정 3. 쿠버네티스에는 다른 Runtime을 사용 했을 수 있고, 같은 이미지더라도 사용하는 Runtime에 따라서 이미지의 크기는 달라질 것이다.일프로 님의 설명에 따르면, Docker는 다른 많은 기능들을 지원해 주기 때문에 (ContainerD 외에도) 실제 이미지가 248.26MB라고 하더라도, 다운 받은 이후 자신의 매타데이터 규격에 맞게 데이터들을 더 추가하고 이미지를 재구성 합니다. 그래서 490MB로 사이즈가 늘어난것!Containerd에서 이미지를 파일로 바꿔 복사를 해도, Docker 상에서 돌아가는 이미지를 구성할 때 데이터들을 추가해주니 사이즈가 늘어난거라 이해하면 될것 같다.즉, 우리는 컨테이너 이미지를 받을 때, 쿠버네티스에서 ContainerD를 사용해 컨테이너를 동작시키는 경우, Docker를 통해 이미지를 만들 경우 불필요한 데이터로 인해 이미지 사이즈가 더 커지게 될 수 있다는 걸 확인했다.

데브옵스 · 인프라k8sci/cd

양파쿵야

쿠버네티스 어나더 클래스 지상편: Sprint2 Day16 ArgoCD 2

DevOps 엔지니어가 배포를 해야되는 상황DevOps 엔지니어는 리소스 스펙 변경이 필요할 때, App 버전이 업그레이드 될 때 컨테이너 이미지를 변경해 배포를 해야 한다.원래 DevOps 엔지니어는 App 버전을 교체할 때 YAML 파일을 수정해야하지만, Helm을 사용하면 배포 명령에 이미지 태그를 동적으로 부여하므로 YAML 파일 수정 없이 자동 배포가 가능하다. ArgoCD Image Updater를 사용해야 하는 이유ArgoCD가 이미지 변경을 감지하여 자동으로 K8s로 배포한다.다만 Jenkins가 아닌 ArgoCD가 감지하여 배포하므로, 컨테이너 빌드가 끝난 이후에 자동 배포가 어려워졌다. → Jenkins가 YAML파일을 수정하고 Git에 업그레이드 하는 방법은 로직이 복잡해진다.⇒ ArgoCD Image Update가 도커 허브를 모니터링하고 이미지 업데이트가 감지되면 ArgoCD에 배포 명령을 전송, K8s로 자동 배포를 수행한다. ArgoCD Image Update 요구사항ArgoCD Image Update는 내부적으로 --set image.tag 명령을 사용하기 때문에 Helm, Kustomize 배포 시에만 사용 가능하다.Image Update와 도커 허브 연결 설정이 필요하다.배포시 태그 규칙 추가가 필요하다. 4. Argo Image Updater 를 이용한 이미지 자동 배포 (helm) - 22324-1. Image Updater values-dev.yaml 파일 확인4-3. Jenkins에서 배포4-4. Image Updater 동작 확인설정한 로그가 없어 정보가 결과가 없음. 각 이미지마다 alias를 설정해야한다. Git에서 삭제하더라도 K8s에서 리소스를 유지할 지 여부, 내용 출돌시 Git의 변경을 자동으로 반영할 지 여부: Git과 항상 동일한 형상을 유지하고 싶을 때 사용할 수 있다. → K8s의 오토스케일링이 발생해도 Git과 형상을 유지하기 위해 다시 돌아간다.(강의 영상처럼 분명 SYNC 켰는데 들어가보면 꺼져있음) 4-6. 도커 빌드 Job 생성 3가지 환경에 배포해봤지만 변화가 없다...

데브옵스 · 인프라워밍업클럽4기

하얀종이개발자

인프런 워밍업 스터디 클럽 4기 데브옵스 - 미션5 (Docker와 Containerd)

Docker와 Containerd 명령 실습 [미션5]쿠버네티스 설치 시 Docker Hub에서 여러 이미지를 다운로드하는 과정에서, "toomanyrequests" 에러가 발생할 수 있음. 이유는 Docker Hub의 요청 제한 정책 때문익명 사용자: 6시간 동안 최대 100건로그인 사용자: 6시간 동안 최대 200건회사에서 여러 사람이 같은 IP로 요청하면 제한에 쉽게 걸릴 수 있음6시간을 기다리는 것이 아니라 다른 우회 방법을 찾고자 함 방법- 개인 PC인 경우: 휴대폰 테더링으로 IP를 바꿔 우회 가능- 회사 내부망 전용 PC/VM의 경우: 이미지를 다른 경로(복사 등)로 전달하는 방법을 고려해야 함 결론- 네트워크 제약이 있는 환경이라면 이미지 복사 등 대안이 필요- 제한을 우회하려면 IP 분리 또는 프록시 등의 방법을 고민할 수 있음 내 개인 노트북을 통해서 이미지를 다운 받고 -> 쿠버네티스가 있는 서버에 복사 하는 플로우 예시 [도커 6]->[도커 7]->[컨테이너디 7] 순으로 작업 dockercontainerdDocker 명령어 실습사전 준비(코드 다운로드)도커 파일 및 App 소스 다운로드curl -O https://raw.githubusercontent.com/k8s-1pro/install/main/ground/etc/docker/Dockerfilecurl -O https://raw.githubusercontent.com/k8s-1pro/install/main/ground/etc/docker/hello.js  전체 실습 명령어docker build -t noah1209/hello:1.0.0 .docker image listdocker tag noah1209/hello:1.0.0 noah1209/hello:2.0.0docker login -u noah1209docker push noah1209/hello:1.0.0docker rmi noah1209/hello:1.0.0docker pull noah1209/hello:1.0.0docker save -o file.tar noah1209/hello:1.0.0docker load -i file.tar 빌드이미지 리스트 조회태그 변경로그인 및 이미지 업로드이미지 삭제이미지 다운로드이미지 -> 파일로 변환파일 -> 이미지로 변환 Containerd 명령어 실습전체 실습 명령어ctr ns listctr -n k8s.io image listctr images pull docker.io/noah1209/hello:1.0.0ctr images tag docker.io/noah1209/hello:1.0.0 docker.io/noah1209/hello:2.0.0ctr image push docker.io/noah1209/hello:2.0.0 --user ratschectr -n default image export file.tar docker.io/noah1209/hello:1.0.0ctr -n k8s.io image import file.tarctr -n k8s.io image remove docker.io/noah1209/hello:1.0.0 네임스페이스 조회특정 네임스페이스 내 이미지 조회다운로드 및 이미지 확인태그 변경업로드이미지 -> 파일로 변환파일 -> 이미지(namespace : k8s.io)로 변환삭제 (namespace : k8s.io) 같은 이미지를 도커에서 받았을 때와 쿠버네티스에서 받았을 때 사이즈가 다른 이유 Docker와 Containerd에서 다운로드 받고 이미지 Size를 확인Docker 다운로드 -> 520MBContainerd 다운로드 -> 247.8MB분석같은 이미지를 받았는데 사이즈가 이렇게 다를 수 있나? 싶었습니다.Docker로 1pro/api-tester:latest 이미지를 받았을 땐 520MBContainerd로 받았을 땐 247.8MB처음엔 "혹시 Docker는 amd64 버전을 받고, Containerd는 arm64로 받아서 그런가?" 의심했지만,두 환경 모두 linux/amd64 플랫폼에서 테스트한 결과, 이건 아니었습니다.Containerd에서 PLATFORMS 항목에 여러 아키텍처가 표시되는 건,"이 이미지는 여러 플랫폼을 지원한다"는 정보일 뿐,여러 플랫폼의 레이어를 실제로 다 받아온 건 아니더라고요.그렇다면 왜 사이즈 차이가 날까요? 간단히 말하면, Docker는 이미지를 조금 더 '포장'해서 보관합니다.Docker는 이미지 내에 각종 히스토리, 빌드 정보, 메타데이터 등을 추가로 저장하고, 이걸 자기만의 방식으로 압축하고 재구성해요. 반면 Containerd는 꼭 필요한 것만 가져다 쓰는 경량화 버전입니다.실제로 Docker에서 이미지를 save해서 파일로 만든 후 Containerd로 가져가면, 파일 사이즈는 줄어들고 그 반대는 오히려 파일 사이즈가 커졌습니다. 결론결국 사이즈 차이는 런타임의 성격 차이에서 비롯된 것 같습니다.Docker는 만능툴답게 이미지에 이것저것 부가 정보를 더 많이 붙입니다. 그래서 같은 이미지라도 더 크게 보이고,Containerd는 핵심만 챙기는 실속형 런타임이라 같은 이미지라도 더 작고 가볍게 보입니다.그렇기 때문에 오프라인 환경에서 이미지 파일을 주고받을 때는, 사용 중인 런타임에 맞춰 이미지 저장 방식도 맞추는 게 좋습니다. 예를 들어, Kubernetes에서 Containerd를 쓰고 있다면 Docker로 받은 이미지보다 Containerd에서 직접 받은 이미지 파일을 쓰는 게 더 효율적이라고 생각합니다.

백엔드일프로워밍업클럽데브옵스

_hamtaro_o

미션 #5. 컨테이너 이미지 사례 실습

     빌드 docker build -t test/hello:1.0.0 . [+] Building 12.3s (8/8) FINISHED docker:desktop-linux => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 97B 0.0s => [internal] load metadata for docker.io/library/node:slim 2.3s => [auth] library/node:pull token for registry-1.docker.io 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load build context 0.0s => => transferring context: 215B 0.0s => [1/2] FROM docker.io/library/node:slim@sha256:b30c143a092c7dced8e17ad67a8783c03234d4844ee 9.6s => => resolve docker.io/library/node:slim@sha256:b30c143a092c7dced8e17ad67a8783c03234d4844ee 0.0s => => sha256:34ef2a75627f6089e01995bfd3b3786509bbdc7cfb4dbc804b642e195340d 28.08MB / 28.08MB 7.7s => => sha256:00b6bc59183634774862a1f5d9fa777966ffdd8b4edd6fe07006671358dfc24 3.31kB / 3.31kB 0.7s => => sha256:7293ae927b976710c33b54ae3957471f36b9e1150408853c3dfbd7baff3f5 50.52MB / 50.52MB 8.7s => => sha256:b30c143a092c7dced8e17ad67a8783c03234d4844ee84c39090c9780491aaf8 5.20kB / 5.20kB 0.0s => => sha256:af442a7998c3f3a985309cfa7b709ea8d3f1911ea19a598f1f1a2e158273c73 1.93kB / 1.93kB 0.0s => => sha256:85878ac12a824d35ede83635c5aa0a6b4c83fe0b8fa5fb125e1fc839a5af01a 6.59kB / 6.59kB 0.0s => => sha256:148b7926ba2143f7dbd1efaab45bd08b5fde13f01510d1319ee7cd0aa781f8d 1.71MB / 1.71MB 1.5s => => sha256:0a5428d7ed1bdde6d0638d39b519fcd3307eb60e70ba9f220d1066b39a71de93 447B / 447B 1.9s => => extracting sha256:34ef2a75627f6089e01995bfd3b3786509bbdc7cfb4dbc804b642e195340dbc9 0.8s => => extracting sha256:00b6bc59183634774862a1f5d9fa777966ffdd8b4edd6fe07006671358dfc249 0.0s => => extracting sha256:7293ae927b976710c33b54ae3957471f36b9e1150408853c3dfbd7baff3f59d1 0.8s => => extracting sha256:148b7926ba2143f7dbd1efaab45bd08b5fde13f01510d1319ee7cd0aa781f8d0 0.0s => => extracting sha256:0a5428d7ed1bdde6d0638d39b519fcd3307eb60e70ba9f220d1066b39a71de93 0.0s => [2/2] COPY hello.js . 0.2s => exporting to image 0.1s => => exporting layers 0.0s => => writing image sha256:7d635123c7017af009e6818217e513383410b544c4f5aad555221a02b1b4e1d7 0.0s => => naming to docker.io/hello:1.0.0 0.0s  이미지 조회docker image list REPOSITORY TAG IMAGE ID CREATED SIZE /hello 1.0.0 7d635123c701 2 minutes ago 249MB jenkins/jenkins lts-jdk17 eb3da18f5f0b 8 months ago 499MB kindest/node <none> 1cf551538f7d 16 months ago 96 이미지 태그 변경docker login -u hamtaro Password: Login Succeeded 이미지 푸쉬docker push /hello:1.0.0 The push refers to repository [docker.io/hello] ab1c299e0236: Pushed a04dc377afe1: Mounted from library/node 1b2a793e9797: Mounted from library/node 0fa9dab4f369: Mounted from library/node abb3903f11f9: Mounted from library/node 6edfb9bfff29: Mounted from library/node 1.0.0: digest: sha256:603e375fb7f34d7f376f13c8193864b914742d186371f60842c6cfa99132bd9a size: 1574 이미지 삭제docker rmi -f 7d635123701 Untagged: /hello:1.0.0 Untagged: /hello:2.0.0 Untagged: /hello@sha256:603e375fb7f34d7f376f13c8193864b914742d186371f6c6cfa99132bd9a Deleted: sha256:7d635123c7017af009e6818217e5133844c4f5aad555221a02b1b4e1d7 이미지 다운로드docker pull /hello:1.0.0 1.0.0: Pulling from /hello 34ef2a75627f: Already exists 00b6bc591836: Already exists 7293ae927b97: Already exists 148b7926ba21: Already exists 0a5428d7ed1b: Already exists d03369722173: Already exists Digest: sha256:603e375fb7f34d7f376f13c81186371f60842c6cfa99132bd9a Status: Downloaded newer image for /hello:1.0.0 docker.io/hello:1.0.0 이미지 파일 변환docker save -o file.tar 7d635123c701 ls Dockerfile file.tar hello.js docker load -i file.tar Loaded image ID: 7d635123c7017af009e6818217e513383410b544c4f5aad555221a02b1b4e1d7 containerd[root@k8s-master ~]# ctr ns list NAME LABELS k8s.io [root@k8s-master ~]# ctr -n k8s.io image list REF TYPE DIGEST SIZE PLATFORMS LABELS docker.io/1pro/api-tester:v1.0.0 application/vnd.oci.image.index.v1+json sha256:6b38dd347b66c7f14c393280a040831a72b4a93fd5beddc011ee852c26f35058 247.8 MiB linux/amd64,linux/arm64,unknown/unknown io.cri-containerd.image=managed docker.io/1pro/api-tester:v2.0.0 ... [root@k8s-master ~]# ctr images pull docker.io/sd0241/hello:1.0.0 docker.io/sd0241/hello:1.0.0: resolved |++++++++++++++++++++++++++++++++++++++| manifest-sha256:603e375fb7f34d7f376f13c8193864b914742d186371f60842c6cfa99132bd9a: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:00b6bc59183634774862a1f5d9fa777966ffdd8b4edd6fe07006671358dfc249: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:d0336972217335effba593a6a5da5d1732e7c19c5953843cffb2e71d279196e7: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:148b7926ba2143f7dbd1efaab45bd08b5fde13f01510d1319ee7cd0aa781f8d0: done |++++++++++++++++++++++++++++++++++++++| config-sha256:7d635123c7017af009e6818217e513383410b544c4f5aad555221a02b1b4e1d7: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:0a5428d7ed1bdde6d0638d39b519fcd3307eb60e70ba9f220d1066b39a71de93: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:7293ae927b976710c33b54ae3957471f36b9e1150408853c3dfbd7baff3f59d1: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:34ef2a75627f6089e01995bfd3b3786509bbdc7cfb4dbc804b642e195340dbc9: done |++++++++++++++++++++++++++++++++++++++| elapsed: 12.1s total: 76.6 M (6.3 MiB/s) unpacking linux/arm64/v8 sha256:603e375fb7f34d7f376f13c8193864b914742d186371f60842c6cfa99132bd9a... done: 1.269243327s [root@k8s-master ~]# ctr ns list NAME LABELS default k8s.io [root@k8s-master ~]# ctr images list REF TYPE DIGEST SIZE PLATFORMS LABELS docker.io/sd0241/hello:1.0.0 application/vnd.docker.distribution.manifest.v2+json sha256:603e375fb7f34d7f376f13c8193864b914742d186371f60842c6cfa99132bd9a 76.6 MiB linux/arm64 - [root@k8s-master ~]# ctr images tag docker.io/sd0241/hello:1.0.0 docker.io/sd0241/hello:2.0.0 docker.io/sd0241/hello:2.0.0 [root@k8s-master ~]# ctr images list REF TYPE DIGEST SIZE PLATFORMS LABELS docker.io/sd0241/hello:1.0.0 application/vnd.docker.distribution.manifest.v2+json sha256:603e375fb7f34d7f376f13c8193864b914742d186371f60842c6cfa99132bd9a 76.6 MiB linux/arm64 - docker.io/sd0241/hello:2.0.0 application/vnd.docker.distribution.manifest.v2+json sha256:603e375fb7f34d7f376f13c8193864b914742d186371f60842c6cfa99132bd9a 76.6 MiB linux/arm64 - [root@k8s-master ~]# ctr images tag docker.io/sd0241/hello:1.0.0 docker.io/sd0241/hello:2.0.0 docker.io/sd0241/hello:2.0.0 [root@k8s-master ~]# ctr images list REF TYPE DIGEST SIZE PLATFORMS LABELS docker.io/sd0241/hello:1.0.0 application/vnd.docker.distribution.manifest.v2+json sha256:603e375fb7f34d7f376f13c8193864b914742d186371f60842c6cfa99132bd9a 76.6 MiB linux/arm64 - docker.io/sd0241/hello:2.0.0 application/vnd.docker.distribution.manifest.v2+json sha256:603e375fb7f34d7f376f13c8193864b914742d186371f60842c6cfa99132bd9a 76.6 MiB linux/arm64 - [root@k8s-master ~]# ctr image push docker.io/sd0241/hello:2.0.0 --user sd0241 Password: manifest-sha256:603e375fb7f34d7f376f13c8193864b914742d186371f60842c6cfa99132bd9a: done |++++++++++++++++++++++++++++++++++++++| config-sha256:7d635123c7017af009e6818217e513383410b544c4f5aad555221a02b1b4e1d7: done |++++++++++++++++++++++++++++++++++++++| elapsed: 3.0 s 

데브옵스 · 인프라쿠버네티스일프로

Docker와 Containerd 명령 실습 [미션5]

해당 게시물은 쿠버네티스 어나더 클래스 (지상편) - Sprint 1, 2 강의와 강의 자료를 수강한 뒤 작성하였습니다.인프런 러닝업 클럽의 [미션 5]에 해당하는 게시물입니다.도커▶ 사전 준비사항# 도커 파일 및 App 소스 다운로드 curl -O https://raw.githubusercontent.com/k8s-1pro/install/main/ground/etc/docker/Dockerfile curl -O https://raw.githubusercontent.com/k8s-1pro/install/main/ground/etc/docker/hello.js▶ 업로드 실습을 해보기 위해서는 본인의 도커 허브 Username 필요본인 도커 허브 Username : hoonzzang<실습 시작>​1. 빌드[root@cicd-server mission]# docker build -t hoonzzang/hello:1.0.0 . [+] Building 9.9s (7/7) FINISHED docker:default => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 157B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/node:slim 4.2s => [internal] load build context 0.0s => => transferring context: 275B 0.0s => [1/2] FROM docker.io/library/node:slim@sha256:b30c143a092c7dced8e17ad67a8783c03234d4844ee84c3 5.3s => => resolve docker.io/library/node:slim@sha256:b30c143a092c7dced8e17ad67a8783c03234d4844ee84c3 0.0s => => sha256:1a6a7b2e2e2c80a6973f57aa8b0c6ad67a961ddbc5ef326c448e133f93564ff9 1.93kB / 1.93kB 0.0s => => sha256:26c0b956ed16dae9780bcb6c24f8161b3f8d44339c435691372d8fe1f270d97b 6.57kB / 6.57kB 0.0s => => sha256:dad67da3f26bce15939543965e09c4059533b025f707aad72ed3d3f3a09c66f8 28.23MB / 28.23MB 1.6s => => sha256:ea9602600a53af802a015c3d6bc5298ce2b6dff888a6f93b2861465f710804c2 3.31kB / 3.31kB 1.6s => => sha256:e03b89ff903664199350b286d7985167de4c079a4ed44baefc09cc1d2e0395ca 51.04MB / 51.04MB 3.3s => => sha256:b30c143a092c7dced8e17ad67a8783c03234d4844ee84c39090c9780491aaf89 5.20kB / 5.20kB 0.0s => => sha256:b03d7a90d937df6cc4c0c2e094b722156a78951c3b5cbe9c383f9a735ea3c316 1.71MB / 1.71MB 2.0s => => sha256:748509dbfbee9fa52f4b018cdaefbc837ee275e458fbdd76b96b312b764a27ac 447B / 447B 1.9s => => extracting sha256:dad67da3f26bce15939543965e09c4059533b025f707aad72ed3d3f3a09c66f8 1.5s => => extracting sha256:ea9602600a53af802a015c3d6bc5298ce2b6dff888a6f93b2861465f710804c2 0.0s => => extracting sha256:e03b89ff903664199350b286d7985167de4c079a4ed44baefc09cc1d2e0395ca 1.5s => => extracting sha256:b03d7a90d937df6cc4c0c2e094b722156a78951c3b5cbe9c383f9a735ea3c316 0.2s => => extracting sha256:748509dbfbee9fa52f4b018cdaefbc837ee275e458fbdd76b96b312b764a27ac 0.0s => [2/2] COPY hello.js . 0.3s => exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:f6ef74ec70ee892aecc61799ec1ef2d1e435a8b4cc9e6fbda64800f7738e30d0 0.0s => => naming to docker.io/hoonzzang/hello:1.0.0 0.0s ​2. 이미지 리스트 조회[root@cicd-server mission]# docker image list REPOSITORY TAG IMAGE ID CREATED SIZE hoonzzang/hello 1.0.0 f6ef74ec70ee 5 minutes ago 230MB 3. 태그 변경[root@cicd-server mission]# docker tag hoonzzang/hello:1.0.0 hoonzzang/hello:2.0.0 [root@cicd-server mission]# docker image list REPOSITORY TAG IMAGE ID CREATED SIZE hoonzzang/hello 1.0.0 f6ef74ec70ee 6 minutes ago 230MB hoonzzang/hello 2.0.0 f6ef74ec70ee 6 minutes ago 230MB 4-1. 로그인[root@cicd-server mission]# docker login -u hoonzzang Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded 4-2. 이미지 업로드[root@cicd-server mission]# docker push hoonzzang/hello:1.0.0 The push refers to repository [docker.io/hoonzzang/hello] d6097db963bb: Pushed 8a45580a6679: Mounted from library/node d5b49e0b6f8f: Mounted from library/node eaf814c4be3d: Mounted from library/node 59cd39de7802: Mounted from library/node 7fb72a7d1a8e: Mounted from library/node 1.0.0: digest: sha256:ca358dd2d3526da7622485c8c9bb813ada128b771136a6113234e0a4d13b4b3b size: 1574 5. 이미지 삭제[root@cicd-server mission]# docker rmi hoonzzang/hello:1.0.0 Untagged: hoonzzang/hello:1.0.0 [root@cicd-server mission]# docker rmi hoonzzang/hello:2.0.0 Untagged: hoonzzang/hello:2.0.0 Untagged: hoonzzang/hello@sha256:ca358dd2d3526da7622485c8c9bb813ada128b771136a6113234e0a4d13b4b3b Deleted: sha256:f6ef74ec70ee892aecc61799ec1ef2d1e435a8b4cc9e6fbda64800f7738e30d0 6. 이미지 다운로드[root@cicd-server mission]# docker pull hoonzzang/hello:1.0.0 1.0.0: Pulling from hoonzzang/hello dad67da3f26b: Already exists ea9602600a53: Already exists e03b89ff9036: Already exists b03d7a90d937: Already exists 748509dbfbee: Already exists 9e44e6272433: Already exists Digest: sha256:ca358dd2d3526da7622485c8c9bb813ada128b771136a6113234e0a4d13b4b3b Status: Downloaded newer image for hoonzzang/hello:1.0.0 docker.io/hoonzzang/hello:1.0.0 7. 이미지 -> 파일로 변환[root@cicd-server mission]# docker save -o file.tar hoonzzang/hello:1.0.0 [root@cicd-server mission]# ls Dockerfile file.tar hello.js [root@cicd-server mission]# ls file.tar file.tar ▶ 이미지 삭제[root@cicd-server mission]# docker rmi hoonzzang/hello:1.0.0 Untagged: hoonzzang/hello:1.0.0 Untagged: hoonzzang/hello@sha256:ca358dd2d3526da7622485c8c9bb813ada128b771136a6113234e0a4d13b4b3b Deleted: sha256:f6ef74ec70ee892aecc61799ec1ef2d1e435a8b4cc9e6fbda64800f7738e30d0 8. 파일 -> 이미지로 변환[root@cicd-server mission]# docker load -i file.tar Loaded image: hoonzzang/hello:1.0.0 [root@cicd-server mission]# docker image list REPOSITORY TAG IMAGE ID CREATED SIZE hoonzzang/hello 1.0.0 f6ef74ec70ee 12 minutes ago 230MB ▶ 정리[root@cicd-server mission]# docker rmi hoonzzang/hello:1.0.0 Untagged: hoonzzang/hello:1.0.0 Deleted: sha256:f6ef74ec70ee892aecc61799ec1ef2d1e435a8b4cc9e6fbda64800f7738e30d0 [root@cicd-server mission]# rm file.tar rm: remove regular file 'file.tar'? yes 컨테이너디 (Containerd) <실습 시작>​1. 네임스페이스 조회[root@k8s-master ~]# ctr ns list NAME LABELS k8s.io  2. 특정 네임스페이스 내 이미지 조회[root@k8s-master ~]# ctr -n k8s.io image list REF TYPE DIGEST SIZE PLATFORMS LABELS docker.io/1pro/api-tester:v1.0.0 application/vnd.oci.image.index.v1+json sha256:6b38dd347b66c7f14c393280a040831a72b4a93fd5beddc011ee852c26f35058 248.3 MiB linux/amd64,linux/arm64,unknown/unknown io.cri-containerd.image=managed docker.io/1pro/api-tester:v2.0.0 application/vnd.oci.image.index.v1+json sha256:eed09de27648c5e13a7978069e1af63908bf4c6fd023d73de993e8b6abf556b4 248.3 MiB linux/amd64,linux/arm64,unknown/unknown io.cri-containerd.image=managed docker.io/1pro/api-tester@sha256:6b38dd347b66c7f14c393280a040831a72b4a93fd5beddc011ee852c26f35058 application/vnd.oci.image.index.v1+json sha256:6b38dd347b66c7f14c393280a040831a72b4a93fd5beddc011ee852c26f35058 248.3 MiB linux/amd64,linux/arm64,unknown/unknown io.cri-containerd.image=managed docker.io/1pro/api-tester@sha256:eed09de27648c5e13a7978069e1af63908bf4c6fd023d73de993e8b6abf556b4 application/vnd.oci.image.index.v1+json sha256:eed09de27648c5e13a7978069e1af63908bf4c6fd023d73de993e8b6abf556b4 248.3 MiB linux/amd64,linux/arm64,unknown/unknown io.cri-containerd.image=managed docker.io/1pro/app:latest application/vnd.oci.image.index.v1+json sha256:9d81d340d25b6bf7ec48e742cc149c170cdf8c94263da540a7d7034be476bd6b 248.3 MiB linux/amd64,linux/arm64,unknown/unknown io.cri-containerd.image=managed docker.io/1pro/app@sha256:9d81d340d25b6bf7ec48e742cc149c170cdf8c94263da540a7d7034be476bd6b application/vnd.oci.image.index.v1+json sha256:9d81d340d25b6bf7ec48e742cc149c170cdf8c94263da540a7d7034be476bd6b 248.3 MiB linux/amd64,linux/arm64,unknown/unknown io.cri-containerd.image=managed docker.io/calico/apiserver:v3.26.4 application/vnd.docker.distribution.manifest.list.v2+json sha256:c520f71091cd09a9c9628a4e010f6fbc6118da9573af46af5b3f4c3ed8d463dc 37.8 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/calico/apiserver@sha256:c520f71091cd09a9c9628a4e010f6fbc6118da9573af46af5b3f4c3ed8d463dc application/vnd.docker.distribution.manifest.list.v2+json sha256:c520f71091cd09a9c9628a4e010f6fbc6118da9573af46af5b3f4c3ed8d463dc 37.8 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/calico/cni:v3.26.4 application/vnd.docker.distribution.manifest.list.v2+json sha256:7c5895c5d6ed3266bcd405fbcdbb078ca484688673c3479f0f18bf072d58c242 89.4 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/calico/cni@sha256:7c5895c5d6ed3266bcd405fbcdbb078ca484688673c3479f0f18bf072d58c242 application/vnd.docker.distribution.manifest.list.v2+json sha256:7c5895c5d6ed3266bcd405fbcdbb078ca484688673c3479f0f18bf072d58c242 89.4 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/calico/csi:v3.26.4 application/vnd.docker.distribution.manifest.list.v2+json sha256:0ab0fafee845c82c1a31bc2a3d5df29768626d570fbbead4813ad0da4a4ebf4b 8.6 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/calico/csi@sha256:0ab0fafee845c82c1a31bc2a3d5df29768626d570fbbead4813ad0da4a4ebf4b application/vnd.docker.distribution.manifest.list.v2+json sha256:0ab0fafee845c82c1a31bc2a3d5df29768626d570fbbead4813ad0da4a4ebf4b 8.6 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/calico/kube-controllers:v3.26.4 application/vnd.docker.distribution.manifest.list.v2+json sha256:5fce14b4dfcd63f1a4663176be4f236600b410cd896d054f56291c566292c86e 31.4 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/calico/kube-controllers@sha256:5fce14b4dfcd63f1a4663176be4f236600b410cd896d054f56291c566292c86e application/vnd.docker.distribution.manifest.list.v2+json sha256:5fce14b4dfcd63f1a4663176be4f236600b410cd896d054f56291c566292c86e 31.4 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/calico/node-driver-registrar:v3.26.4 application/vnd.docker.distribution.manifest.list.v2+json sha256:77db9df0ecd41c514d8dcab3b2681091f98f8d70e29a03df12c086a4e032639b 10.7 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/calico/node-driver-registrar@sha256:77db9df0ecd41c514d8dcab3b2681091f98f8d70e29a03df12c086a4e032639b application/vnd.docker.distribution.manifest.list.v2+json sha256:77db9df0ecd41c514d8dcab3b2681091f98f8d70e29a03df12c086a4e032639b 10.7 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/calico/node:v3.26.4 application/vnd.docker.distribution.manifest.list.v2+json sha256:a8b77a5f27b167501465f7f5fb7601c44af4df8dccd1c7201363bbb301d1fe40 85.3 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/calico/node@sha256:a8b77a5f27b167501465f7f5fb7601c44af4df8dccd1c7201363bbb301d1fe40 application/vnd.docker.distribution.manifest.list.v2+json sha256:a8b77a5f27b167501465f7f5fb7601c44af4df8dccd1c7201363bbb301d1fe40 85.3 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/calico/pod2daemon-flexvol:v3.26.4 application/vnd.docker.distribution.manifest.list.v2+json sha256:cf169a0c328a5b4f2dc96b224c3cf6dbc2c8269c6ecafac54bc1de00102b665e 7.1 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/calico/pod2daemon-flexvol@sha256:cf169a0c328a5b4f2dc96b224c3cf6dbc2c8269c6ecafac54bc1de00102b665e application/vnd.docker.distribution.manifest.list.v2+json sha256:cf169a0c328a5b4f2dc96b224c3cf6dbc2c8269c6ecafac54bc1de00102b665e 7.1 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/calico/typha:v3.26.4 application/vnd.docker.distribution.manifest.list.v2+json sha256:ebe99272d38ff65255c1fba33c17d10f588b612625b19c68fe5aeed0f134fa74 26.9 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/calico/typha@sha256:ebe99272d38ff65255c1fba33c17d10f588b612625b19c68fe5aeed0f134fa74 application/vnd.docker.distribution.manifest.list.v2+json sha256:ebe99272d38ff65255c1fba33c17d10f588b612625b19c68fe5aeed0f134fa74 26.9 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/grafana/grafana:9.5.2 application/vnd.docker.distribution.manifest.list.v2+json sha256:39c849cebccccb22c0a5194f07c535669386190e029aa440ad535226974a5809 84.9 MiB linux/amd64,linux/arm/v7,linux/arm64/v8 io.cri-containerd.image=managed docker.io/grafana/grafana@sha256:39c849cebccccb22c0a5194f07c535669386190e029aa440ad535226974a5809 application/vnd.docker.distribution.manifest.list.v2+json sha256:39c849cebccccb22c0a5194f07c535669386190e029aa440ad535226974a5809 84.9 MiB linux/amd64,linux/arm/v7,linux/arm64/v8 io.cri-containerd.image=managed docker.io/grafana/loki:2.6.1 application/vnd.docker.distribution.manifest.list.v2+json sha256:1ee60f980950b00e505bd564b40f720132a0653b110e993043bb5940673d060a 19.2 MiB linux/amd64,linux/arm/v7,linux/arm64/v8 io.cri-containerd.image=managed docker.io/grafana/loki@sha256:1ee60f980950b00e505bd564b40f720132a0653b110e993043bb5940673d060a application/vnd.docker.distribution.manifest.list.v2+json sha256:1ee60f980950b00e505bd564b40f720132a0653b110e993043bb5940673d060a 19.2 MiB linux/amd64,linux/arm/v7,linux/arm64/v8 io.cri-containerd.image=managed docker.io/grafana/promtail:2.7.4 application/vnd.docker.distribution.manifest.list.v2+json sha256:db66221bcc9510f3101121d42354b19c83cb810c5480e4936eb75c43443656f4 69.4 MiB linux/amd64,linux/arm/v7,linux/arm64/v8 io.cri-containerd.image=managed docker.io/grafana/promtail@sha256:db66221bcc9510f3101121d42354b19c83cb810c5480e4936eb75c43443656f4 application/vnd.docker.distribution.manifest.list.v2+json sha256:db66221bcc9510f3101121d42354b19c83cb810c5480e4936eb75c43443656f4 69.4 MiB linux/amd64,linux/arm/v7,linux/arm64/v8 io.cri-containerd.image=managed docker.io/hoonzzang/api-tester:v1.0.0 application/vnd.docker.distribution.manifest.v2+json sha256:9d2e4e0da69986c5d270a8f781d5535a41a2ea727cc6089c36750c99508c911e 248.3 MiB linux/amd64 io.cri-containerd.image=managed docker.io/hoonzzang/api-tester@sha256:9d2e4e0da69986c5d270a8f781d5535a41a2ea727cc6089c36750c99508c911e application/vnd.docker.distribution.manifest.v2+json sha256:9d2e4e0da69986c5d270a8f781d5535a41a2ea727cc6089c36750c99508c911e 248.3 MiB linux/amd64 io.cri-containerd.image=managed docker.io/kubernetesui/dashboard:v2.7.0 application/vnd.docker.distribution.manifest.list.v2+json sha256:2e500d29e9d5f4a086b908eb8dfe7ecac57d2ab09d65b24f588b1d449841ef93 72.3 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/kubernetesui/dashboard@sha256:2e500d29e9d5f4a086b908eb8dfe7ecac57d2ab09d65b24f588b1d449841ef93 application/vnd.docker.distribution.manifest.list.v2+json sha256:2e500d29e9d5f4a086b908eb8dfe7ecac57d2ab09d65b24f588b1d449841ef93 72.3 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/kubernetesui/metrics-scraper:v1.0.8 application/vnd.docker.distribution.manifest.list.v2+json sha256:76049887f07a0476dc93efc2d3569b9529bf982b22d29f356092ce206e98765c 18.8 MiB linux/amd64,linux/arm,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed docker.io/kubernetesui/metrics-scraper@sha256:76049887f07a0476dc93efc2d3569b9529bf982b22d29f356092ce206e98765c application/vnd.docker.distribution.manifest.list.v2+json sha256:76049887f07a0476dc93efc2d3569b9529bf982b22d29f356092ce206e98765c 18.8 MiB linux/amd64,linux/arm,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed quay.io/brancz/kube-rbac-proxy:v0.14.1 application/vnd.docker.distribution.manifest.list.v2+json sha256:58d91a5faaf8f8222f8aa6c0a170826bbabcc60eedab71afd2326548cde84171 23.5 MiB linux/amd64,linux/arm,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed quay.io/brancz/kube-rbac-proxy@sha256:58d91a5faaf8f8222f8aa6c0a170826bbabcc60eedab71afd2326548cde84171 application/vnd.docker.distribution.manifest.list.v2+json sha256:58d91a5faaf8f8222f8aa6c0a170826bbabcc60eedab71afd2326548cde84171 23.5 MiB linux/amd64,linux/arm,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed quay.io/prometheus-operator/prometheus-config-reloader:v0.65.2 application/vnd.docker.distribution.manifest.list.v2+json sha256:18632ea5cff38cda5b08054057297e527dcfc144a5f195c1c836a0805a9bbad1 5.1 MiB linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x io.cri-containerd.image=managed quay.io/prometheus-operator/prometheus-config-reloader@sha256:18632ea5cff38cda5b08054057297e527dcfc144a5f195c1c836a0805a9bbad1 application/vnd.docker.distribution.manifest.list.v2+json sha256:18632ea5cff38cda5b08054057297e527dcfc144a5f195c1c836a0805a9bbad1 5.1 MiB linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x io.cri-containerd.image=managed quay.io/prometheus-operator/prometheus-operator:v0.65.2 application/vnd.docker.distribution.manifest.list.v2+json sha256:5c3da991d54f5ff9b84e5a1fb55110b4de7fcd00723367eff6f90392ad01e79b 16.2 MiB linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x io.cri-containerd.image=managed quay.io/prometheus-operator/prometheus-operator@sha256:5c3da991d54f5ff9b84e5a1fb55110b4de7fcd00723367eff6f90392ad01e79b application/vnd.docker.distribution.manifest.list.v2+json sha256:5c3da991d54f5ff9b84e5a1fb55110b4de7fcd00723367eff6f90392ad01e79b 16.2 MiB linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x io.cri-containerd.image=managed quay.io/prometheus/node-exporter:v1.6.0 application/vnd.docker.distribution.manifest.list.v2+json sha256:d2e48098c364e61ee62d9016eed863b66331d87cf67146f2068b70ed9d9b4f98 11.2 MiB linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x io.cri-containerd.image=managed quay.io/prometheus/node-exporter@sha256:d2e48098c364e61ee62d9016eed863b66331d87cf67146f2068b70ed9d9b4f98 application/vnd.docker.distribution.manifest.list.v2+json sha256:d2e48098c364e61ee62d9016eed863b66331d87cf67146f2068b70ed9d9b4f98 11.2 MiB linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x io.cri-containerd.image=managed quay.io/prometheus/prometheus:v2.44.0 application/vnd.docker.distribution.manifest.list.v2+json sha256:0f0b7feb6f02620df7d493ad7437b6ee95b6d16d8d18799f3607124e501444b1 88.7 MiB linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x io.cri-containerd.image=managed quay.io/prometheus/prometheus@sha256:0f0b7feb6f02620df7d493ad7437b6ee95b6d16d8d18799f3607124e501444b1 application/vnd.docker.distribution.manifest.list.v2+json sha256:0f0b7feb6f02620df7d493ad7437b6ee95b6d16d8d18799f3607124e501444b1 88.7 MiB linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x io.cri-containerd.image=managed quay.io/tigera/operator:v1.30.9 application/vnd.docker.distribution.manifest.list.v2+json sha256:431f037ff18b5c867d01312e42671effc55602421aeed25dd3f6109f70596b4a 19.8 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed quay.io/tigera/operator@sha256:431f037ff18b5c867d01312e42671effc55602421aeed25dd3f6109f70596b4a application/vnd.docker.distribution.manifest.list.v2+json sha256:431f037ff18b5c867d01312e42671effc55602421aeed25dd3f6109f70596b4a 19.8 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed registry.k8s.io/coredns/coredns:v1.10.1 application/vnd.docker.distribution.manifest.list.v2+json sha256:a0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e 15.4 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/mips64le,linux/ppc64le,linux/s390x io.cri-containerd.image=managed registry.k8s.io/coredns/coredns@sha256:a0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e application/vnd.docker.distribution.manifest.list.v2+json sha256:a0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e 15.4 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/mips64le,linux/ppc64le,linux/s390x io.cri-containerd.image=managed registry.k8s.io/etcd:3.5.7-0 application/vnd.docker.distribution.manifest.list.v2+json sha256:51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83 96.9 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x,windows/amd64 io.cri-containerd.image=managed registry.k8s.io/etcd@sha256:51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83 application/vnd.docker.distribution.manifest.list.v2+json sha256:51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83 96.9 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x,windows/amd64 io.cri-containerd.image=managed registry.k8s.io/kube-apiserver:v1.27.16 application/vnd.docker.distribution.manifest.list.v2+json sha256:77fe7968e3b27222e2719b3df7efa37494e0504497b865b19e2595ef5f790520 32.3 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed registry.k8s.io/kube-apiserver@sha256:77fe7968e3b27222e2719b3df7efa37494e0504497b865b19e2595ef5f790520 application/vnd.docker.distribution.manifest.list.v2+json sha256:77fe7968e3b27222e2719b3df7efa37494e0504497b865b19e2595ef5f790520 32.3 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed registry.k8s.io/kube-controller-manager:v1.27.16 application/vnd.docker.distribution.manifest.list.v2+json sha256:25ccfb06da9ceabfdfcb6826925b4ea0dc7b271beec5355ad49ca8687ebcad67 30.0 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed registry.k8s.io/kube-controller-manager@sha256:25ccfb06da9ceabfdfcb6826925b4ea0dc7b271beec5355ad49ca8687ebcad67 application/vnd.docker.distribution.manifest.list.v2+json sha256:25ccfb06da9ceabfdfcb6826925b4ea0dc7b271beec5355ad49ca8687ebcad67 30.0 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed registry.k8s.io/kube-proxy:v1.27.16 application/vnd.docker.distribution.manifest.list.v2+json sha256:f775c9f86ed22956ceae174ee9474aa8044f2a675b72124d566b7d7ac866b249 26.4 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed registry.k8s.io/kube-proxy@sha256:f775c9f86ed22956ceae174ee9474aa8044f2a675b72124d566b7d7ac866b249 application/vnd.docker.distribution.manifest.list.v2+json sha256:f775c9f86ed22956ceae174ee9474aa8044f2a675b72124d566b7d7ac866b249 26.4 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed registry.k8s.io/kube-scheduler:v1.27.16 application/vnd.docker.distribution.manifest.list.v2+json sha256:c36386d8885561c417e2bf59dbb38989e4dac25f3d2bd95f7d3fd7e475847a57 17.3 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed registry.k8s.io/kube-scheduler@sha256:c36386d8885561c417e2bf59dbb38989e4dac25f3d2bd95f7d3fd7e475847a57 application/vnd.docker.distribution.manifest.list.v2+json sha256:c36386d8885561c417e2bf59dbb38989e4dac25f3d2bd95f7d3fd7e475847a57 17.3 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.9.2 application/vnd.docker.distribution.manifest.list.v2+json sha256:5ac2e67a862cd3baa0eb4fd7683d54928fd76ea3a61cde50508922c956901d8c 12.7 MiB linux/amd64,linux/arm,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed registry.k8s.io/kube-state-metrics/kube-state-metrics@sha256:5ac2e67a862cd3baa0eb4fd7683d54928fd76ea3a61cde50508922c956901d8c application/vnd.docker.distribution.manifest.list.v2+json sha256:5ac2e67a862cd3baa0eb4fd7683d54928fd76ea3a61cde50508922c956901d8c 12.7 MiB linux/amd64,linux/arm,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed registry.k8s.io/metrics-server/metrics-server:v0.6.3 application/vnd.docker.distribution.manifest.list.v2+json sha256:c60778fa1c44d0c5a0c4530ebe83f9243ee6fc02f4c3dc59226c201931350b10 28.6 MiB linux/amd64,linux/arm,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed registry.k8s.io/metrics-server/metrics-server@sha256:c60778fa1c44d0c5a0c4530ebe83f9243ee6fc02f4c3dc59226c201931350b10 application/vnd.docker.distribution.manifest.list.v2+json sha256:c60778fa1c44d0c5a0c4530ebe83f9243ee6fc02f4c3dc59226c201931350b10 28.6 MiB linux/amd64,linux/arm,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed registry.k8s.io/pause:3.6 application/vnd.docker.distribution.manifest.list.v2+json sha256:3d380ca8864549e74af4b29c10f9cb0956236dfb01c40ca076fb6c37253234db 294.7 KiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x,windows/amd64 io.cri-containerd.image=managed registry.k8s.io/pause:3.9 application/vnd.docker.distribution.manifest.list.v2+json sha256:7031c1b283388d2c2e09b57badb803c05ebed362dc88d84b480cc47f72a21097 314.0 KiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x,windows/amd64 io.cri-containerd.image=managed registry.k8s.io/pause@sha256:3d380ca8864549e74af4b29c10f9cb0956236dfb01c40ca076fb6c37253234db application/vnd.docker.distribution.manifest.list.v2+json sha256:3d380ca8864549e74af4b29c10f9cb0956236dfb01c40ca076fb6c37253234db 294.7 KiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x,windows/amd64 io.cri-containerd.image=managed registry.k8s.io/pause@sha256:7031c1b283388d2c2e09b57badb803c05ebed362dc88d84b480cc47f72a21097 application/vnd.docker.distribution.manifest.list.v2+json sha256:7031c1b283388d2c2e09b57badb803c05ebed362dc88d84b480cc47f72a21097 314.0 KiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x,windows/amd64 io.cri-containerd.image=managed registry.k8s.io/prometheus-adapter/prometheus-adapter:v0.10.0 application/vnd.docker.distribution.manifest.list.v2+json sha256:2f34cb3a04a0fee6034f4d63ce3ee7786c0f762dc9f3bf196c70e894dd92edd1 28.1 MiB linux/amd64,linux/arm,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed registry.k8s.io/prometheus-adapter/prometheus-adapter@sha256:2f34cb3a04a0fee6034f4d63ce3ee7786c0f762dc9f3bf196c70e894dd92edd1 application/vnd.docker.distribution.manifest.list.v2+json sha256:2f34cb3a04a0fee6034f4d63ce3ee7786c0f762dc9f3bf196c70e894dd92edd1 28.1 MiB linux/amd64,linux/arm,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:02337dea82f1d6776e89acb28b9bd6b0e1a571552c321c8dae3a3cd09b8f10d6 application/vnd.oci.image.index.v1+json sha256:eed09de27648c5e13a7978069e1af63908bf4c6fd023d73de993e8b6abf556b4 248.3 MiB linux/amd64,linux/arm64,unknown/unknown io.cri-containerd.image=managed sha256:07655ddf2eebe5d250f7a72c25f638b27126805d61779741b4e62e69ba080558 application/vnd.docker.distribution.manifest.list.v2+json sha256:2e500d29e9d5f4a086b908eb8dfe7ecac57d2ab09d65b24f588b1d449841ef93 72.3 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:08a0bfca3fbb866e63ea5b601d44877ff76fbe3b054b4e0af06494501d5b0eb3 application/vnd.oci.image.index.v1+json sha256:6b38dd347b66c7f14c393280a040831a72b4a93fd5beddc011ee852c26f35058 248.3 MiB linux/amd64,linux/arm64,unknown/unknown io.cri-containerd.image=managed sha256:1113933272f1e851cbb93d4922cc9765a8f8a7a0f8ba668188f8b46d353d9fc5 application/vnd.docker.distribution.manifest.list.v2+json sha256:77fe7968e3b27222e2719b3df7efa37494e0504497b865b19e2595ef5f790520 32.3 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:115053965e86b2df4d78af78d7951b8644839d20a03820c6df59a261103315f7 application/vnd.docker.distribution.manifest.list.v2+json sha256:76049887f07a0476dc93efc2d3569b9529bf982b22d29f356092ce206e98765c 18.8 MiB linux/amd64,linux/arm,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:173d3570a5af2b2ef8816b40af3ca985280549520e8d328a7f20333d9f354d1b application/vnd.docker.distribution.manifest.list.v2+json sha256:d2e48098c364e61ee62d9016eed863b66331d87cf67146f2068b70ed9d9b4f98 11.2 MiB linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:17d35f5bad38f1d00ee41111d6655540797ec5011740a733b706b4717d300ede application/vnd.docker.distribution.manifest.list.v2+json sha256:7c5895c5d6ed3266bcd405fbcdbb078ca484688673c3479f0f18bf072d58c242 89.4 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:1da78bf35ce712c624e66a97ee43ee1c223acc6e41f57f00b0e9d8509072ecf8 application/vnd.docker.distribution.manifest.list.v2+json sha256:58d91a5faaf8f8222f8aa6c0a170826bbabcc60eedab71afd2326548cde84171 23.5 MiB linux/amd64,linux/arm,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:2db343b95a4c2dd01357c800499a1e111dbd825e174bf57fab148f08cd135ccf application/vnd.docker.distribution.manifest.list.v2+json sha256:25ccfb06da9ceabfdfcb6826925b4ea0dc7b271beec5355ad49ca8687ebcad67 30.0 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:2df54f2d834883a3a24b6380d7378c0078d589a947b6ce89b669b1e9596ac306 application/vnd.docker.distribution.manifest.list.v2+json sha256:431f037ff18b5c867d01312e42671effc55602421aeed25dd3f6109f70596b4a 19.8 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:33e977a8921d4750e95e77c0c30a510bfe4e50b5b92bca50c668c39d92f0aec7 application/vnd.docker.distribution.manifest.list.v2+json sha256:c520f71091cd09a9c9628a4e010f6fbc6118da9573af46af5b3f4c3ed8d463dc 37.8 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:42dd24636051991ba549340ec7312c07f189708de8e57674da53dcb11a5c8315 application/vnd.docker.distribution.manifest.list.v2+json sha256:1ee60f980950b00e505bd564b40f720132a0653b110e993043bb5940673d060a 19.2 MiB linux/amd64,linux/arm/v7,linux/arm64/v8 io.cri-containerd.image=managed sha256:5269a4e7c596c0dfffc4922e05db348f71ab78017279fe27a7cebd942b274b99 application/vnd.docker.distribution.manifest.list.v2+json sha256:0ab0fafee845c82c1a31bc2a3d5df29768626d570fbbead4813ad0da4a4ebf4b 8.6 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:6270bb605e12e581514ada5fd5b3216f727db55dc87d5889c790e4c760683fee application/vnd.docker.distribution.manifest.list.v2+json sha256:3d380ca8864549e74af4b29c10f9cb0956236dfb01c40ca076fb6c37253234db 294.7 KiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x,windows/amd64 io.cri-containerd.image=managed sha256:67469ed830756ddf7bbfea7022dabeac7290346236d92987f31c149bdd8378df application/vnd.docker.distribution.manifest.list.v2+json sha256:ebe99272d38ff65255c1fba33c17d10f588b612625b19c68fe5aeed0f134fa74 26.9 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:6c5313ea00cc57f404a3d7a2967f674e21bcfc9172f6d5558d204f461b90b3b7 application/vnd.docker.distribution.manifest.list.v2+json sha256:39c849cebccccb22c0a5194f07c535669386190e029aa440ad535226974a5809 84.9 MiB linux/amd64,linux/arm/v7,linux/arm64/v8 io.cri-containerd.image=managed sha256:75972a31ad256ca862df92e395141ef811a4213f265d6d338455e863adbf73fa application/vnd.docker.distribution.manifest.list.v2+json sha256:0f0b7feb6f02620df7d493ad7437b6ee95b6d16d8d18799f3607124e501444b1 88.7 MiB linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:77db55adb93bf28d40299429757423595a6e0d87c367a3e6c8019e516c2a56da application/vnd.docker.distribution.manifest.list.v2+json sha256:5c3da991d54f5ff9b84e5a1fb55110b4de7fcd00723367eff6f90392ad01e79b 16.2 MiB linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:78e4198d60e924f58ae4e9dbcf647dfe0fc72eb594fba3a9f0f35b98eeb3a759 application/vnd.docker.distribution.manifest.list.v2+json sha256:db66221bcc9510f3101121d42354b19c83cb810c5480e4936eb75c43443656f4 69.4 MiB linux/amd64,linux/arm/v7,linux/arm64/v8 io.cri-containerd.image=managed sha256:791bf87161b80649906f4af26cb2562771f1f98b94a31358db9a6ee8761da27e application/vnd.docker.distribution.manifest.v2+json sha256:9d2e4e0da69986c5d270a8f781d5535a41a2ea727cc6089c36750c99508c911e 248.3 MiB linux/amd64 io.cri-containerd.image=managed sha256:817bbe3f2e5179b5fa7dd4085c87aab1faaf9dc879e3b1d05796901a006f58ab application/vnd.docker.distribution.manifest.list.v2+json sha256:c60778fa1c44d0c5a0c4530ebe83f9243ee6fc02f4c3dc59226c201931350b10 28.6 MiB linux/amd64,linux/arm,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:8465800dbe52dc0ca865e06af0b2ec37a4ff38e7baefa3285a18d809f084be0d application/vnd.docker.distribution.manifest.list.v2+json sha256:5ac2e67a862cd3baa0eb4fd7683d54928fd76ea3a61cde50508922c956901d8c 12.7 MiB linux/amd64,linux/arm,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:86b6af7dd652c1b38118be1c338e9354b33469e69a218f7e290a0ca5304ad681 application/vnd.docker.distribution.manifest.list.v2+json sha256:51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83 96.9 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x,windows/amd64 io.cri-containerd.image=managed sha256:91ad8454afddc4daa2217c19ea39700e0bd99fb0997ff5316cff450197064a98 application/vnd.docker.distribution.manifest.list.v2+json sha256:c36386d8885561c417e2bf59dbb38989e4dac25f3d2bd95f7d3fd7e475847a57 17.3 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:98013c939b20e1abb864e5e965f67305c38ef09228cdb4ca12f180b8ec04f6df application/vnd.docker.distribution.manifest.list.v2+json sha256:18632ea5cff38cda5b08054057297e527dcfc144a5f195c1c836a0805a9bbad1 5.1 MiB linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:b32f991981530a0795906b5cda923c5bb5d949f25cd915d78c8ee665fafbeec8 application/vnd.docker.distribution.manifest.list.v2+json sha256:5fce14b4dfcd63f1a4663176be4f236600b410cd896d054f56291c566292c86e 31.4 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:db40998d424e93956fb6b50b9a0ab3e05a780ca8215c695b368cae3a471e3ba1 application/vnd.oci.image.index.v1+json sha256:9d81d340d25b6bf7ec48e742cc149c170cdf8c94263da540a7d7034be476bd6b 248.3 MiB linux/amd64,linux/arm64,unknown/unknown io.cri-containerd.image=managed sha256:ded66453eb630bd4d4efddee2ccf290cbca4c67bca07c2d53c35c35dd0251136 application/vnd.docker.distribution.manifest.list.v2+json sha256:a8b77a5f27b167501465f7f5fb7601c44af4df8dccd1c7201363bbb301d1fe40 85.3 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:e6f1816883972d4be47bd48879a08919b96afcd344132622e4d444987919323c application/vnd.docker.distribution.manifest.list.v2+json sha256:7031c1b283388d2c2e09b57badb803c05ebed362dc88d84b480cc47f72a21097 314.0 KiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x,windows/amd64 io.cri-containerd.image=managed sha256:e92afb5b902be1049756335c5338f820efb0192b208113d06a3ac0454ce32663 application/vnd.docker.distribution.manifest.list.v2+json sha256:2f34cb3a04a0fee6034f4d63ce3ee7786c0f762dc9f3bf196c70e894dd92edd1 28.1 MiB linux/amd64,linux/arm,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:e9d4fd70e7d9c5d60a1b0bdd375950c77518a83b184bf3770cba99a0b5a83610 application/vnd.docker.distribution.manifest.list.v2+json sha256:cf169a0c328a5b4f2dc96b224c3cf6dbc2c8269c6ecafac54bc1de00102b665e 7.1 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:ea1f910af975c6eb292175cf49f168c2cfd425fb50c75a51fd0b40e262c68b12 application/vnd.docker.distribution.manifest.list.v2+json sha256:f775c9f86ed22956ceae174ee9474aa8044f2a675b72124d566b7d7ac866b249 26.4 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:ead0a4a53df89fd173874b46093b6e62d8c72967bbf606d672c9e8c9b601a4fc application/vnd.docker.distribution.manifest.list.v2+json sha256:a0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e 15.4 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/mips64le,linux/ppc64le,linux/s390x io.cri-containerd.image=managed sha256:f5a1fb28a3f1ee8b37046c32abef11c4d458adc045d4668c3910a2e7f6b2930a application/vnd.docker.distribution.manifest.list.v2+json sha256:77db9df0ecd41c514d8dcab3b2681091f98f8d70e29a03df12c086a4e032639b 10.7 MiB linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed  3. 다운로드 및 이미지 확인 (이미지는 default라는 네임스페이스에 다운 받아집니다.)[root@k8s-master ~]# ctr images pull docker.io/hoonzzang/hello:1.0.0 docker.io/hoonzzang/hello:1.0.0: resolved |++++++++++++++++++++++++++++++++++++++| manifest-sha256:ca358dd2d3526da7622485c8c9bb813ada128b771136a6113234e0a4d13b4b3b: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:9e44e62724332abe502c4710b8427ef0ff326666807a3a47267b74d99cdd0390: done |++++++++++++++++++++++++++++++++++++++| config-sha256:f6ef74ec70ee892aecc61799ec1ef2d1e435a8b4cc9e6fbda64800f7738e30d0: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:dad67da3f26bce15939543965e09c4059533b025f707aad72ed3d3f3a09c66f8: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:ea9602600a53af802a015c3d6bc5298ce2b6dff888a6f93b2861465f710804c2: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:e03b89ff903664199350b286d7985167de4c079a4ed44baefc09cc1d2e0395ca: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:b03d7a90d937df6cc4c0c2e094b722156a78951c3b5cbe9c383f9a735ea3c316: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:748509dbfbee9fa52f4b018cdaefbc837ee275e458fbdd76b96b312b764a27ac: done |++++++++++++++++++++++++++++++++++++++| elapsed: 7.6 s total: 77.2 M (10.2 MiB/s) unpacking linux/amd64 sha256:ca358dd2d3526da7622485c8c9bb813ada128b771136a6113234e0a4d13b4b3b... done: 2.843976863s [root@k8s-master ~]# ctr ns list NAME LABELS default k8s.io [root@k8s-master ~]# ctr images list REF TYPE DIGEST SIZE PLATFORMS LABELS docker.io/hoonzzang/hello:1.0.0 application/vnd.docker.distribution.manifest.v2+json sha256:ca358dd2d3526da7622485c8c9bb813ada128b771136a6113234e0a4d13b4b3b 77.2 MiB linux/amd64 -  4. 태그 변경[root@k8s-master ~]# ctr images tag docker.io/hoonzzang/hello:1.0.0 docker.io/hoonzzang/hello:2.0.0 docker.io/hoonzzang/hello:2.0.0 [root@k8s-master ~]# ctr images list REF TYPE DIGEST SIZE PLATFORMS LABELS docker.io/hoonzzang/hello:1.0.0 application/vnd.docker.distribution.manifest.v2+json sha256:ca358dd2d3526da7622485c8c9bb813ada128b771136a6113234e0a4d13b4b3b 77.2 MiB linux/amd64 - docker.io/hoonzzang/hello:2.0.0 application/vnd.docker.distribution.manifest.v2+json sha256:ca358dd2d3526da7622485c8c9bb813ada128b771136a6113234e0a4d13b4b3b 77.2 MiB linux/amd64 -  5. 업로드[root@k8s-master ~]# ctr image push docker.io/hoonzzang/hello:2.0.0 --user hoonzzang Password: manifest-sha256:ca358dd2d3526da7622485c8c9bb813ada128b771136a6113234e0a4d13b4b3b: done |++++++++++++++++++++++++++++++++++++++| config-sha256:f6ef74ec70ee892aecc61799ec1ef2d1e435a8b4cc9e6fbda64800f7738e30d0: done |++++++++++++++++++++++++++++++++++++++| elapsed: 3.4 s total: 8.9 Ki (2.6 KiB/s)  6. 이미지 (namespace : default) -> 파일로 변환[root@k8s-master ~]# ctr -n default image export file.tar docker.io/hoonzzang/hello:1.0.0 [root@k8s-master ~]# ls file.tar file.tar 7. 파일 -> 이미지로 변환 (namespace : k8s.io)[root@k8s-master ~]# ctr -n k8s.io image import file.tar unpacking docker.io/hoonzzang/hello:1.0.0 (sha256:ca358dd2d3526da7622485c8c9bb813ada128b771136a6113234e0a4d13b4b3b)...done [root@k8s-master ~]# ctr -n k8s.io image list | grep hello docker.io/hoonzzang/hello:1.0.0 application/vnd.docker.distribution.manifest.v2+json sha256:ca358dd2d3526da7622485c8c9bb813ada128b771136a6113234e0a4d13b4b3b 77.2 MiB linux/amd64 io.cri-containerd.image=managed  8. 삭제 (namespace : k8s.io)[root@k8s-master ~]# ctr -n k8s.io image remove docker.io/hoonzzang/hello:1.0.0 docker.io/hoonzzang/hello:1.0.0 [root@k8s-master ~]# ctr -n k8s.io image list | grep hello  [번외수업] 같은 이미지를 도커에서 받았을 때와 쿠버네티스에서 받았을 때 사이즈가 다른 이유▶ Docker (490MB)[root@cicd-server ~]# docker pull hoonzzang/api-tester:v1.0.0 v1.0.0: Pulling from hoonzzang/api-tester 38a980f2cc8a: Already exists de849f1cfbe6: Already exists a7203ca35e75: Already exists 9434e39ea4e0: Already exists 4f4fb700ef54: Already exists Digest: sha256:9291559e6e75b033a43c598b745d6ecbec188c69baf50301bd033b472b85f0de Status: Downloaded newer image for hoonzzang/api-tester:v1.0.0 docker.io/hoonzzang/api-tester:v1.0.0 [root@cicd-server ~]# docker image list REPOSITORY TAG IMAGE ID CREATED SIZE hoonzzang/api-tester v1.0.0 0160bdcf08a2 2 days ago 490MB ▶ Containerd (248.3 MiB)[root@k8s-master ~]# ctr image pull docker.io/hoonzzang/api-tester:v1.0.0 docker.io/hoonzzang/api-tester:v1.0.0: resolved |++++++++++++++++++++++++++++++++++++++| manifest-sha256:9291559e6e75b033a43c598b745d6ecbec188c69baf50301bd033b472b85f0de: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1: done |++++++++++++++++++++++++++++++++++++++| config-sha256:0160bdcf08a27dd0134fe8907066f9159bc7abb20c00e3e7d4fde0ef6595878e: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:38a980f2cc8accf69c23deae6743d42a87eb34a54f02396f3fcfd7c2d06e2c5b: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:de849f1cfbe60b1c06a1db83a3129ab0ea397c4852b98e3e4300b12ee57ba111: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:a7203ca35e75e068651c9907d659adc721dba823441b78639fde66fc988f042f: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:9434e39ea4e0d667bc6aed21b2845da55c923fe22d06bf8cf575f3c1f26da7b1: done |++++++++++++++++++++++++++++++++++++++| elapsed: 7.6 s total: 246.9 (32.5 MiB/s) unpacking linux/amd64 sha256:9291559e6e75b033a43c598b745d6ecbec188c69baf50301bd033b472b85f0de... done: 5.818201977s [root@k8s-master ~]# ctr image list REF TYPE DIGEST SIZE PLATFORMS LABELS docker.io/hoonzzang/api-tester:v1.0.0 application/vnd.docker.distribution.manifest.v2+json sha256:9291559e6e75b033a43c598b745d6ecbec188c69baf50301bd033b472b85f0de 248.3 MiB linux/amd64 -   ==> 도커에서는 컨테이너 관리시 사용자 편의를 위해 다양한 추가 기능들이 들어있는데, 이 때문에 컨테이너 이미지를 도커로 가져올 때 이미지 본연의 크기보다 크게 잡히게 됩니다. 반면 Contaienrd를 사용하게 되면 도커에 비해서 작은 사이즈의 이미지를 가져올 수 있게 됩니다.그러나 위의 실습처럼 도커에서 가져온 이미지를 다시 Contaienrd로 가져오게 된다면 도커가 기본적으로 제공하는 추가 기능들로 인해 커진 이미지의 크기를 그대로 들어가 불필요하게 이미지가 커지게 됩니다. 

쿠버네티스일프로러닝업클럽

채널톡 아이콘