반응형

테스트 케이스를 작성을 할때 내가 어렵게 생각했던것은 2가지 이다.

1. Mock 으로 테스트케이스를 작성할 것인가? 아니면 실제 데이터를 가지고 작성할 것인다.

2. 테스트용 DB를 따로 둬야 할까?

이 2가지가 항상 풀리지 않는 난제 같았다. 그런데 갑자기 뭔가 기준을 정해서 하면 되지 않을까 라는 생각이 들었다. 어떻게 보면 당연한 이야기 이긴 하지만. 테스트케이스를 작성하려는 클래스들의 역할에 생각해 보고 그에 맞는 테스트 케이스를 작성하면 되는 것이다. 

Spring Boot 프로젝트를 보면 테스트케이스를 작성하는 클래스들로 다음과 같은 것들을 꼽을 수 있다.

1. Repository
2. Service
3. Controller
4. RestApiController

그럼 우선 이번 글에서는 Repository 에 대해서만 살펴보려고 한다. Repository 는 실제로 DB 와 연결되어서 CRUD를 할 수 있는 클래스이다. Repository 클래스에 정의되어 있는 메소드를 통해서 내가 원하는 데이터를 가져올 수 있는지, 아니면 수정이 되는지 여부를 확인 하는 테스트를 작성하면 된다. 그리고 이부분은 결국 DB의 데이터가 필요하다.  Mock 으로 하기에는 실제 데이터를 가져오는지 여부가 의심(?) 스럽기 때문이다. 

@DataJpaTest
@RunWith(SpringRunner.class)
public class UserRepositoryTest {

    @Autowired
    private UserRepository userRepository;

    private Users users;
    @Before
    public void setup(){
        users = Users.builder()
                .email("test@test.com")
                .name("test")
                .status(UserStatus.APPLIED)
                .build();

        userRepository.save(users);
    }

    @Test
    public void getUsers(){
        List<Users> all = userRepository.findAll();
        Assert.assertNotNull(all);
        Assert.assertEquals(1, all.size());
    }

    @Test
    public void getUsersById(){
        Optional<Users> byId = userRepository.findById("test@test.com");
        Assert.assertNotNull(byId);
        Assert.assertEquals("test", byId.get().getName());
    }
}

@DataJpaTest 를 사용하면 테스트케이스 실행시에 MemoryDB 를 사용해서 실행을 한다.  테스트케이스를 실행해 보면 다음과 같은 로그를 볼 수 있다. 

Hibernate: drop table if exists users CASCADE 
Hibernate: create table users (email varchar(100) not null, name varchar(100) not null, user_status integer not null, primary key (email))
2021-02-17 10:56:06.114  INFO 2856 --- [    Test worker] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2021-02-17 10:56:06.120  INFO 2856 --- [    Test worker] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2021-02-17 10:56:06.224  INFO 2856 --- [    Test worker] c.p.common.user.web.UserRepositoryTest   : Started UserRepositoryTest in 2.808 seconds (JVM running for 3.635)
2021-02-17 10:56:06.293  INFO 2856 --- [    Test worker] o.s.t.c.transaction.TransactionContext   : Began transaction (1) for test context [DefaultTestContext@588bc70b testClass = UserRepositoryTest, testInstance = com.polpid.common.user.web.UserRepositoryTest@4f8e0671, testMethod = getUsers@UserRepositoryTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@34cf76 testClass = UserRepositoryTest, locations = '{}', classes = '{class com.polpid.common.user.SpringCommonUserApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@127dfcc0, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@d5d4db2d, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@5948c9fa, [ImportsContextCustomizer@efe207e key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration, org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManagerAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@61218ded, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@e767673, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.context.SpringBootTestArgs@1], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@4bc55dd0]; rollback [true]
Hibernate: select users0_.email as email1_0_0_, users0_.name as name2_0_0_, users0_.user_status as user_sta3_0_0_ from users users0_ where users0_.email=?
Hibernate: insert into users (name, user_status, email) values (?, ?, ?)
Hibernate: select users0_.email as email1_0_, users0_.name as name2_0_, users0_.user_status as user_sta3_0_ from users users0_
2021-02-17 10:56:06.747  INFO 2856 --- [    Test worker] o.s.t.c.transaction.TransactionContext   : Rolled back transaction for test: [DefaultTestContext@588bc70b testClass = UserRepositoryTest, testInstance = com.polpid.common.user.web.UserRepositoryTest@4f8e0671, testMethod = getUsers@UserRepositoryTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@34cf76 testClass = UserRepositoryTest, locations = '{}', classes = '{class com.polpid.common.user.SpringCommonUserApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@127dfcc0, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@d5d4db2d, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@5948c9fa, [ImportsContextCustomizer@efe207e key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration, org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManagerAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@61218ded, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@e767673, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.context.SpringBootTestArgs@1], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]
2021-02-17 10:56:06.755  INFO 2856 --- [extShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2021-02-17 10:56:06.755  INFO 2856 --- [extShutdownHook] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down'
Hibernate: drop table if exists users CASCADE 

 

테이블을 생성하고 Before 에 정의 되어있는 데로 데이터를 insert 한후 테스트 가 종료되면 테이블을 Drop 한다. 이정도면 Repository에 정의 되어있는 메소드가 내가 생각한대로 동작을 하는지 검증하는데는 크게 문제가 없다. 실제 DB에서 가져오도록 설정도 가능하지만 내 기준에서 테스트는 실제 DB와는 분리 되어야 한다고 생각을 하기 때문에 메모리 DB가 적합한것 같다.

한가지 주의할 점은 도메인을 정의할때 필드를 DB의 예약어와 동일하게 작성을 하면 에러가 날 수 있다. 예를 들어 order 라는 필드가 있으면 테이블이 생성될때 에러가 난다. 

org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "create table users (email varchar(100) not null, name varchar(100) not null, order integer, user_status integer not null, primary key (email))" via JDBC Statement
	at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67) ~[hibernate-core-5.4.18.Final.jar:5.4.18.Final]
	at org.hibernate.tool.schema.internal.SchemaCreatorImpl.applySqlString(SchemaCreatorImpl.java:439) [hibernate-core-5.4.18.Final.jar:5.4.18.Final]
	at org.hibernate.tool.schema.internal.SchemaCreatorImpl.applySqlStrings(SchemaCreatorImpl.java:423) [hibernate-core-5.4.18.Final.jar:5.4.18.Final]
	at org.hibernate.tool.schema.internal.SchemaCreatorImpl.createFromMetadata(SchemaCreatorImpl.java:314) [hibernate-core-5.4.18.Final.jar:5.4.18.Final]
	at org.hibernate.tool.schema.internal.SchemaCreatorImpl.performCreation(SchemaCreatorImpl.java:166) [hibernate-core-5.4.18.Final.jar:5.4.18.Final]
	at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation(SchemaCreatorImpl.java:135) [hibernate-core-5.4.18.Final.jar:5.4.18.Final]
	at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation(SchemaCreatorImpl.java:121) [hibernate-core-5.4.18.Final.jar:5.4.18.Final]
	at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:156) [hibernate-core-5.4.18.Final.jar:5.4.18.Final]
	at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:73) [hibernate-core-5.4.18.Final.jar:5.4.18.Final]
	at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:316) [hibernate-core-5.4.18.Final.jar:5.4.18.Final]
	at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:469) [hibernate-core-5.4.18.Final.jar:5.4.18.Final]
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1259) [hibernate-core-5.4.18.Final.jar:5.4.18.Final]
	at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58) [spring-orm-5.2.8.RELEASE.jar:5.2.8.RELEASE]
	at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) [spring-orm-5.2.8.RELEASE.jar:5.2.8.RELEASE]
	at org

그렇기 때문에 이런 부분들을 조심하면 된다.

Repository 테스트에 대한 결론은 메모리 DB를 사용해서 실제 CRUD 를 테스트 해보면 된다.

이제 다음 글에서는 Service 테스트에 대해서 살펴볼 예정이다.

주의사항) 제 생각을 기준으로 작성하고 만든 소스코드이고 의견이기 때문에 틀린 부분이 있을수 있습니다.

 

728x90
반응형
반응형

static pod 에 대해서 알아보다가 몇가지 기억할 만한 것들을 적어본다.

- master node 의  /etc/kubernetes/manifests 하위에는 yaml 파일들이 있는데 이 yaml 파일들은 마스터 노드가 실행시에 자동으로 생성되는 static pod 들이다. 보통 etcd, api-server등이 있다.

- node에 생성된 static pod 를 지우기 위해서는 해당 노드에 가서 지워야 한다. 지우기 위해서는 노드 안에 있는 kubelet의 config 파일(/var/lib/kubelet/config.yaml) 에 있는 staticPodPath 값을 찾아서 path 위치에 있는 yaml 파일을 지워야 한다. kubectl delete pod 로 지우면 다시 생성된다.

- 조회는 가능하지만 edit 는 불가능 하다.

 

728x90
반응형
반응형

처음에 터미널에서 kubernetes 자동완성 기능을 사용하기 위해 다음과 같이 설정을 했다.

v1-19.docs.kubernetes.io/ko/docs/reference/kubectl/cheatsheet/

 

kubectl 치트 시트

이 페이지는 일반적으로 사용하는 kubectl 커맨드와 플래그에 대한 목록을 포함한다. Kubectl 자동 완성 BASH source <(kubectl completion bash) # bash-completion 패키지를 먼저 설치한 후, bash의 자동 완성을 현재

kubernetes.io

source <(kubectl completion zsh)  # 현재 셸에 zsh의 자동 완성 설정
echo "[[ $commands[kubectl] ]] && source <(kubectl completion zsh)" >> ~/.zshrc # 자동 완성을 zsh 셸에 영구적으로 추가한다.

cheatsheet 에 나온대로 했는데 현제 셸에서는 잘 설정이 되었는데 껐다 다시켜면 안됐다.

그래서 찾아보니 난 oh-my-zsh 를 사용하고 있어서 다른 설정이 추가적으로 필요했다. 다른 설정이 필요했다기 보다는 저 위에 설정은 필요없고 플러그인 설정으로 해결을 할 수 있었다.

cd ~/.oh-my-zsh/custom/plugins/

# zsh-autosuggestions 플러그인 
git clone https://github.com/zsh-users/zsh-autosuggestions 

# zsh-syntax-highlighting 플러그인
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git 

# plugin 활성화 plugins 항목에 다음것들을 추가해주면 된다.
vi ~/.zshrc
plugins=(git zsh-syntax-highlighting zsh-autosuggestions kubectl kube-ps1)

그리고 나서 터미널 재시작 하면 아래와 같이 사용이 가능해진다.

자동완성이 계속 안되서 불편했는데 이제 편해졌다 ^^

 

728x90
반응형
반응형

Discord 를 사용하면서 전체 화면을 공유 했는데 아래와 같이 화면만 나오고 전혀 공유를 할수 없었다.
여기저기 찾아 보다가 해결을 했는데 결과적으로 Mac 설정이 잘못 되어있었다.

시스템 환경설정 > 보안 및 개인 정보 보호 > 화면기록 을 보면 아래와 같이 체크가 안되어있다. 체크를 해주면 자동으로 Discord 가 restart 된다.

재시동 된 후에 화면 공유를 하고 나면 정상적으로 전체 화면이 공유된다.

 

728x90
반응형
반응형

Lens 라는 툴을 사용해 보려고 host pc 에서 VM 에 있는 K8S 를 연결시켜보려고 시도를 해봤다.

2021/01/05 10:08:52 http: proxy error: x509: certificate is valid for 10.96.0.1, 10.0.1.7, not [ip]

그런데 위와 같은 에러 메세지가 나면서 연결이 되지 않았다. 위에 [ip] 는 host pc 의 ip 이다.

Google에서 찾아보니 인증서에 나의 로컬 ip 가 들어가 있지 않아서 라는 이야기가 나왔다.

그럼 현재 k8s 에 있는 apiserver 인증서 내용을 살펴보자.

openssl x509 -in /etc/kubernetes/pki/apiserver.crt -text

위와 같이 입력하면 apiserver.crt 파일에 있는 내용을 출력해서 볼 수 있다. 출력되는 항목중에 Subject Alternative Name 이라는 항목이 있다.

 X509v3 Subject Alternative Name:
                DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, DNS:master01-virtualbox, IP Address:10.96.0.1, IP Address:10.0.1.7

여기 정보를 보면 10.96.0.1, 10.0.1.7 로 정의 되어 있다. 이곳에 내 로컬pc 의 ip 가 정의되어있어야 인증서 오류가 안나게 된다. 그럼 어떻게 해야 저부분을 수정을 할수 있나.

kube-system 네임스페이스에 있는 configmap 중에 kubeadm-config 라는 항목이 있다.

kubectl -n kube-system get configmap kubeadm-config -o yaml

apiVersion: v1
data:
  ClusterConfiguration: |
    apiServer:
      extraArgs:
        authorization-mode: Node,RBAC
      timeoutForControlPlane: 4m0s
    apiVersion: kubeadm.k8s.io/v1beta2
    certificatesDir: /etc/kubernetes/pki
    clusterName: kubernetes
    controllerManager: {}
    dns:
      type: CoreDNS
    etcd:
      local:
        dataDir: /var/lib/etcd
    imageRepository: k8s.gcr.io
    kind: ClusterConfiguration
    kubernetesVersion: v1.19.2
    networking:
      dnsDomain: cluster.local
      podSubnet: 10.244.0.0/16
      serviceSubnet: 10.96.0.0/12
    scheduler: {}
  ClusterStatus: |
    apiEndpoints:
      master01-virtualbox:
        advertiseAddress: 10.0.1.7
        bindPort: 6443
    apiVersion: kubeadm.k8s.io/v1beta2
    kind: ClusterStatus
kind: ConfigMap
metadata:
  creationTimestamp: "2020-10-12T10:21:12Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        .: {}
        f:ClusterConfiguration: {}
        f:ClusterStatus: {}
    manager: kubeadm
    operation: Update
    time: "2020-10-12T10:21:12Z"
  name: kubeadm-config
  namespace: kube-system
  resourceVersion: "168"
  selfLink: /api/v1/namespaces/kube-system/configmaps/kubeadm-config
  uid: 93b6e988-686e-449b-9bd1-a6f02b15d1ea

위처럼 정의 되어있다.

update 를 위해서는 다음과 같이 명령어로 수행해 볼 수 있다.

kubeadm init phase certs --apiserver-cert-extra-sans stringSlice
Optional extra Subject Alternative Names (SANs) to use for the API Server serving certificate. Can be both IP addresses and DNS names.

(kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-init-phase/#cmd-phase-certs)

kubeadmin init phase certs apiserver --apiserver-cert-extra-sans "추가할 IP"

그런데 먼저 하기전에 한가지 더 할 일이 있다.

/etc/kubernetes/pki 에 있는 apiserver.key, apiserver.crt 파일을 다른곳에 옮겨야 한다. 그렇지 않으면 인증서가 새로 생성되지 않는다. 다른 위치에 옮기고 나서 명령어를 실행한다.

sudo kubeadm init phase certs apiserver --apiserver-cert-extra-sans=X.X.X.X
I0105 11:06:44.899381    1295 version.go:252] remote version is much newer: v1.20.1; falling back to: stable-1.19
W0105 11:06:46.225883    1295 configset.go:348] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local master01-virtualbox] and IPs [10.96.0.1 10.0.1.7 X.X.X.X]

위와같이 실행 결과를 볼수 있다. 실제 인증서를 확인해 보면 다음과 같이 들어가 있다.

 X509v3 Subject Alternative Name:
                DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, DNS:master01-virtualbox, IP Address:10.96.0.1, IP Address:10.0.1.7, IP Address:X.X.X.X

그런데 다시 Lens 로 접속 해보니 에러 발생

2021/01/05 13:14:53 http: proxy error: x509: certificate signed by unknown authority

그래서 결국 configmap 도 수정해주고 재기동 한 결과 정상적으로 접속이 됐다.

apiVersion: v1
data:
  ClusterConfiguration: |
    apiServer:
      certSANs:
      - X.X.X.X

 

728x90
반응형
반응형

파드 스케줄링

파드를 만들때 어떤 노드에서 실행할지 다양한 옵션으로 선택할 수 있다.

NodeSelector(노드 셀렉터)

  • 설정
    spec:
      containers:
      nodeSelector:
        key: value

Node Affinity

  • 노드 레이블을 기반으로 파드를 스케줄링 한다.
  • 노드 셀렉터를 함께 설정할 경우 둘다 만족하는 노드에 스케줄링된다.
  • requiredDuringSchedulingIgnoredDuringExecution : 스케줄링 하는동안 꼭 필요한 조건
  • preferredDuringSchedulingIgnoredDuringExecution : 만족하면 좋은 조건. (필수아님)
  • 스케줄링 하는 동안 조건이 변경되더라도 무시한다.
  • 설정
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: beta.kubernetes.io/os
                operator: In
                values:
                - linux
                - window
              - key: disktype
                operator: Exists
          preferredDuringSchedulingIgnoredDuringExecution  
          - weight: 10
            preference:
              matchExpressions:
              - key: kubernetes.io/hostname
                operator: In
                values:
                - worker-node01
    • operators : In, NotIn, Exists, DoesNotExist, Gt(Greater than), Lt(Lower than)

Pod affinity, antiAffinity

  • affinity: 서로 연관성이 있는 Pod 를 같은 노드에 배치
  • antiAffinity: 자원을 많이 차지 하는 Pod 를 서로 다른 노드에 배치
  • 설정
    spec:
        affinity:
          podAntiAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - store
              topologyKey: "kubernetes.io/hostname"
    • app 필드 값이 store 인 노드는 피해서 스케줄링 한다.
    • topologyKey : affinity 를 만족하면 topologyKey 기준으로 같은 노드에 pod 를 실행하고 anitiAffinity를 만족하면 topologyKey 기준으로 다른 노드에 pod 를 실행한다.

taint, toleration

  • 테인트를 설정한 노드는 스케줄링 하지 않는다.
  • 테인트를 설정한 노드에 스케줄링 하려면 톨러레이션을 설정해야 한다.
  • kubectl taint nodes 노드명 key01=value01:NoSchedule (key=value:효과)
  • kubectl taint nodes 노드명 key01=value01:NoSchedule- (테인트 제거)
  • 톨러레이션
    spec:
      tolerations:
      - key: "key01"
        operator: "Equal"
        value: "value01"
        effect: "NoSchedule"
    • effect
      • NoSchedule : 톨러레이션 설정 없으면 스케줄링 안함.
      • PreferNoSchedule : 스케줄링 안하지만 자원 부족하면 할수도 있음
      • NoExecute : 스케줄링 안하며 기존 파드도 설정이 없는경우 종료시킴

cordon, drain

  • cordon
    • 지정한 노드에 추가로 파드를 스케줄링 하지 않는다.
    • kubectl cordon 노드명
      master01@master01-VirtualBox:~$ kubectl get nodes
      NAME                  STATUS     ROLES    AGE   VERSION
      master01-virtualbox   Ready      master   79d   v1.19.2
      worker01-virtualbox   Ready      <none>   79d   v1.19.2
      worker02-virtualbox   NotReady   <none>   79d   v1.19.2
      master01@master01-VirtualBox:~$ kubectl cordon worker01-virtualbox
      node/worker01-virtualbox cordoned
      master01@master01-VirtualBox:~$ kubectl get nodes
      NAME                  STATUS                     ROLES    AGE   VERSION
      master01-virtualbox   Ready                      master   79d   v1.19.2
      worker01-virtualbox   Ready,SchedulingDisabled   <none>   79d   v1.19.2
      worker02-virtualbox   NotReady                   <none>   79d   v1.19.2
      master01@master01-VirtualBox:~$ kubectl uncordon worker01-virtualbox
      node/worker01-virtualbox uncordoned
      master01@master01-VirtualBox:~$ kubectl get nodes
      NAME                  STATUS     ROLES    AGE   VERSION
      master01-virtualbox   Ready      master   79d   v1.19.2
      worker01-virtualbox   Ready      <none>   79d   v1.19.2
      worker02-virtualbox   NotReady   <none>   79d   v1.19.2
  • drain
    • 지정된 노드에 있는 파드를 다른 노드로 옮긴다.
    • 노드에 데몬셋이 존재할 경우 적용 불가능
    • 데몬셋 무시하고 적용할 경우 --ignore-daemonsets=true 옵션 추가
    • 컨트롤러를 이용하지 않은 파드들도 drain 불가능

출처 : 쿠버네티스 입문 - 90가지 예제로 배우는 컨테이너 관리자 자동화 표준 (동양북스)

728x90
반응형
반응형

Secret

  • 비밀번호 같은 민감한 정보를 저장하는 용도로 사용

생성

  • 명령어
    • kubectl create generic secret명 --from-file~
    • 실제 값은 base64 로 인코딩한 값이 들어간다.
  • 템플릿
    apiVersion: v1
    kind: Secret
    metadata:
      name: user-pass-yaml
    type: Opaque
    data:
      username: 값
      password: 값
    • type
      • Opaque : 기본값
      • kubernetes.io/service-account-token : 쿠버네티스 인증토큰 저장
      • kubernetes.io/dockerconfigjson: 도커 저장소 인증정보 저장
      • kubernetes.io/tls: TLS 인증서 저장
    • data 값은 base64 로 인코딩 한 값을 넣어야 한다.
      • echo -n "username" | base64

사용

  • 환경변수로 사용

     

    spec:
      containers:
      - name:
        image:
        env:
        - name: SECRET_USERNAME
          valueFrom:
            secretKeyRef:
              name: user-pass-yaml
              key: username
  • volume 에 바인딩 하기
    spec:
      containers:
      - name:
        image:
        volumeMounts:
        - name: volume-secret
          mountPath: /etc/config
          readOnly: true
      volumes:
      - name: config-secret
        secret:
          secretName: user-pass-yaml 
  • 프라이빗 커네이너 이미지 pull
    • kubectl create secret docker-registry dockersecret --docker-username= --docker-password= --docker-email= --docker-service=https://~
    • 설정
      spec:
      containers:
      - name:
        image:
      imagePullSecrets:
      - name: dockersecret      
  • TLS 사용
    • kubectl create secret tls tlssecret --key tls.key --cert tls.crt

제한

  • secret 은 etcd 에 저장된다.
  • secret의 최대 용량은 1MB
  • 작은 용량의 secret 을 여러개 만들어도 문제가 생길수 있다.
  • etcd 는 접근 제한을 해야 한다.

출처 : 쿠버네티스 입문 - 90가지 예제로 배우는 컨테이너 관리자 자동화 표준 (동양북스)

728x90
반응형
반응형

Label, Annotation

Label(레이블)

  • 키-값 쌍으로 구성
  • 파드 관리할때 구분하는 역할을 한다.
  • 규칙
    • 63글자 넘으면 안됨
    • 시작과 끝문자는 알파벳 대소문자 및 숫자
    • 중간에는 대시(-), 밑줄(_), 점(.), 숫자등이 올수 있음
  • 레이블 셀렉터
    • 등호기반(=, ==)
    • 집합기반(in, notin..)
    • 레이블을 모두 만족시켜야 하는경우 (And) 는 쉼표로 연결
    • 실제 서비스에서 정상적으로 셀렉트를 했는지 보려면 서비스의 endpoint를 확인해보면 된다.
  • pod 선택시 -l 옵션 사용
    • kubectl get pod -l 레이블~

Annotation

  • 쿠버네티스 시스템이 필요한 정보를 담는다.
  • 키는 쿠버네티스 시스템이 인식할 수 있는 값을 사용한다.

출처 : 쿠버네티스 입문 - 90가지 예제로 배우는 컨테이너 관리자 자동화 표준 (동양북스)

728x90
반응형
반응형

ConfigMap

  • 컨테이너에 필요한 환경 설정을 컨테이너와 분리해서 제공하는 기능

사용

  • 설정
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: config-dev
    data:
      DB_URL: localhost
      DB_USER: myuser
      DB_PASS: mypass
      DEBUG_INFO: debug  
  • 컨피그맵 일부만 사용
    spec:
      containers:
      - name:
        image:
        env:
        - name: DEBUG_LEVEL
          valueFrom:
            configMapKeyRef:
              name: config-dev
              key : DEBUG_INFO
    • .env[].valueFrom 사용
    • .env[].valueFrom.configMapKeyRef 를 통해 이미 정의된 configmap 사용
  • 컨피그맵 전체를 불러오기
    spec:
      containers:
      - name:
        image:      
        envFrom:
        - configMapRef:
          name: config-dev      
  • volume 에 바인딩 하기
    spec:
      containers:
      - name:
        image:
        volumeMounts:
        - name: config-volume
          mountPath: /etc/config
      volumes:
      - name: config-volume
        configMap:
          name: config-dev    
    • 컨테이너 내부에 파일로 저장한다.
      root@nginx-deployment-67b8444cdf-sp7lx:/# ls /etc/config/
      DB_PASS  DB_URL  DB_USER  DEBUG_INFO

출처 : 쿠버네티스 입문 - 90가지 예제로 배우는 컨테이너 관리자 자동화 표준 (동양북스)

728x90
반응형

+ Recent posts