인프라/Docker&Kubernetes 2020. 8. 30. 17:02

오늘 다루어볼 내용은 kustomize이다. Kustomize는 kustomization 파일을 이용해 kubernetes 오브젝트를 사용자가 원하는 대로 변경(customize)하는 도구이다.

 

모든 예제는 아래 깃헙 kube-kustomize 디렉토리에 있다.

 

yoonyeoseong/kubernetes-sample

Kubernetes(쿠버네티스) sample. Contribute to yoonyeoseong/kubernetes-sample development by creating an account on GitHub.

github.com

 

kustomization 파일을 포함하는 디렉터리 내의 리소스를 보거나 실제 클러스터에 리소스를 적용하려면 다음 명령어를 이용한다.

 

#kustomize가 적용된 설정파일 결과를 보여준다. 
> kubectl kustomize <kustomization_directory> 
#실제 kustomize 리소스를 클러스터에 적용한다. 
> kubectl apply -k <kustomization_directory>

 

Kustomize

Kustomize는 쿠버네티스 구성을 사용자 정의화하는 도구이다. 이는 애플리케이션 구성 파일을 관리하기 위해 다음 기능들을 가진다.

  • 다른 소스에서 리소스 생성
  • 리소스에 대한 교차 편집 필드 설정
  • 리소스 집합을 구성하고 사용자 정의

 

교차 편집 필드 설정

프로젝트 내 모든 쿠버네티스 리소스에 교차 편집 필드를 설정하는 것은 꽤나 일반적이다. 교차 편집 필드를 설정하는 몇 가지 사용 사례는 다음과 같다.

  • 모든 리소스에 동일한 네임스페이스를 설정
  • 동일한 네임 접두사 또는 접미사를 추가
  • 동일한 레이블들을 추가
  • 동일한 어노테이션들을 추가

 

 

yoonyeoseong/kubernetes-sample

Kubernetes(쿠버네티스) sample. Contribute to yoonyeoseong/kubernetes-sample development by creating an account on GitHub.

github.com

# deployment.yaml을 생성
cat <<EOF >./deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
EOF

cat <<EOF >./kustomization.yaml
namespace: my-namespace
namePrefix: dev-
nameSuffix: "-001"
commonLabels:
  app: bingo
commonAnnotations:
  oncallPager: 800-555-1212
resources:
- deployment.yaml
EOF
> kubectl kustomize ./kube-kustomize/kustomize-upsert-field

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    oncallPager: 800-555-1212
  labels:
    app: bingo
  name: dev-nginx-deployment-001
  namespace: my-namespace
spec:
  selector:
    matchLabels:
      app: bingo
  template:
    metadata:
      annotations:
        oncallPager: 800-555-1212
      labels:
        app: bingo
    spec:
      containers:
      - image: nginx
        name: nginx

 

구성(composition)

한 파일에 deployment, service 등을 정의하는 것은 일반적이다. kustomize는 서로 다른 리소스들을 하나의 파일로 구성할 수 있게 지원한다.

 

 

 

yoonyeoseong/kubernetes-sample

Kubernetes(쿠버네티스) sample. Contribute to yoonyeoseong/kubernetes-sample development by creating an account on GitHub.

github.com

 

# deployment.yaml 파일 생성
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
EOF

# service.yaml 파일 생성
cat <<EOF > service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx
EOF

# 이들을 구성하는 kustomization.yaml 생성
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
- service.yaml
EOF
> kubectl kustomize /kube-kustomize/kustomize-composition

apiVersion: v1
kind: Service
metadata:
  labels:
    run: my-nginx
  name: my-nginx
spec:
  ports:
    - port: 80
      protocol: TCP
  selector:
    run: my-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      run: my-nginx
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
        - image: nginx
          name: my-nginx
          ports:
            - containerPort: 80

 

 

사용자 정의(user patch define)

패치는 리소스에 다른 사용자 정의를 적용하는 데 사용할 수 있다. Kustomize는 patchesStrategicMerge와 patchesJson6902를 통해 서로 다른 패치 메커니즘을 지원한다. patchesStrategicMerge는 파일 경로들의 리스트이다. 각각의 파일은 patchesStrategicMerge로 분석될 수 있어야 한다. 패치 내부의 네임은 반드시 이미 읽혀진 리소스 네임(ex. deployment.yaml 안의 이름)과 일치해야 한다. 한 가지 일을 하는 작은 패치가 권장된다. 예를 들기 위해 디플로이먼트 레플리카 숫자를 증가시키는 하나의 패치와 메모리 상한을 설정하는 다른 패치를 생성한다.

 

 

 

yoonyeoseong/kubernetes-sample

Kubernetes(쿠버네티스) sample. Contribute to yoonyeoseong/kubernetes-sample development by creating an account on GitHub.

github.com

 

 

yoonyeoseong/kubernetes-sample

Kubernetes(쿠버네티스) sample. Contribute to yoonyeoseong/kubernetes-sample development by creating an account on GitHub.

github.com

 

# deployment.yaml 파일 생성
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
EOF

# increase_replicas.yaml 패치 생성
cat <<EOF > increase_replicas.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 3
EOF

# 다른 패치로 set_memory.yaml 생성
cat <<EOF > set_memory.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  template:
    spec:
      containers:
      - name: my-nginx
        resources:
        limits:
          memory: 512Mi
EOF

cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
patchesStrategicMerge:
- increase_replicas.yaml
- set_memory.yaml
EOF
> kubectl kustomize /kube-kustomize/kustomize-patchesStrategicMerge

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      run: my-nginx
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
        - image: nginx
          name: my-nginx
          ports:
            - containerPort: 80
          resources:
            limits:
              memory: 512Mi

 

모든 리소스 또는 필드가 patchesStrategicMerge를 지원하는 것은 아니다. 임의의 리소스 내 임의의 필드의 수정을 지원하기 위해, Kustomize는 patchesJson6902를 통한 JSON 패치 적용을 제공한다. Json 패치의 정확한 리소스를 찾기 위해, 해당 리소스의 group, version, kind, name이 kustomization.yaml 내에 명시될 필요가 있다. 예를 들면, patchesJson6902를 통해 디플로이먼트의 리소스만 증가시킬 수 있다. 또한 patchesStrategicMerge, patchesJson6902를 같이 혼합해서 사용도 가능하다.

 

#deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
        - name: my-nginx
          image: nginx
          ports:
            - containerPort: 80
          resources:
            limits:
              memory: 256Mi

#patch-replica.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 3

#patch-resource.yaml
- op: replace
  path: /spec/template/spec/containers/0/resources/limits/memory
  value: 512Mi

#kustomization.yaml
resources:
  - deployment.yaml

patchesStrategicMerge:
  - patch-replica.yaml

patchesJson6902:
  - target:
      kind: Deployment
      name: my-nginx
      group: apps
      version: v1
    path: patch-resource.yaml
> kubectl kustomize /kube-kustomize/kustomize-patchesJson6902

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      run: my-nginx
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
        - image: nginx
          name: my-nginx
          ports:
            - containerPort: 80
          resources:
            limits:
              memory: 512Mi

 

patchesJson6902는 "replace"라는 오퍼레이션 말고, add, remove, move, copy, test라는 오퍼레이션도 존재한다.

patch images

patch 파일을 생성하지 않고, 컨테이너의 이미지를 재정의 할 수 있다.

 

 

yoonyeoseong/kubernetes-sample

Kubernetes(쿠버네티스) sample. Contribute to yoonyeoseong/kubernetes-sample development by creating an account on GitHub.

github.com

 

cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
EOF

cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
images:
- name: nginx
  newName: my.image.registry/nginx
  newTag: 1.4.0
EOF
> kubectl kustomize /kube-kustomize/kustomize-patch-images

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      run: my-nginx
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
        - image: my.image.registry/nginx:1.4.0
          name: my-nginx
          ports:
            - containerPort: 80

 

Base&Overlay

Kustomize는 base와 overlay의 개념을 가지고 있다. base는 kustomization.yaml과 함께 사용되는 디렉터리다. 이는 사용자 정의와 관련된 리소스들의 집합을 포함한다. kustomization.yaml의 내부에 표시되는 base는 로컬 디렉터리이거나 원격 리포지터리의 디렉터리가 될 수 있다. overlay는 kustomization.yaml이 있는 디렉터리로 다른 kustomization 디렉터리들을 bases로 참조한다. base는 overlay에 대해서 알지 못하며 여러 overlay들에서 사용될 수 있다. 한 overlay는 다수의 base들을 가질 수 있고, base들에서 모든 리소스를 구성할 수 있으며, 이들의 위에 사용자 정의도 가질 수 있다.

 

 

 

yoonyeoseong/kubernetes-sample

Kubernetes(쿠버네티스) sample. Contribute to yoonyeoseong/kubernetes-sample development by creating an account on GitHub.

github.com

# base를 가지는 디렉터리 생성
mkdir base
# base/deployment.yaml 생성
cat <<EOF > base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
EOF

# base/service.yaml 파일 생성
cat <<EOF > base/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx
EOF
# base/kustomization.yaml 생성
cat <<EOF > base/kustomization.yaml
resources:
- deployment.yaml
- service.yaml
EOF

 

이 base는 다수의 overlay에서 사용될 수 있다. 다른 namePrefix 또는 다른 교차 편집 필드들을 서로 다른 overlay에 추가할 수 있다. 다음 예제는 동일한 base를 사용하는 두 overlay들이다.

 

> mkdir dev

cat <<EOF > dev/kustomization.yaml
#구버전 base 불러오는 방법
bases:
  - ../base
#resources:
#- ../base/kustomization.yaml

namespace: dev-my-nginx

patchesStrategicMerge:
  - patch-replica.yaml

patchesJson6902:
  - target:
      kind: Deployment
      name: my-nginx
      group: apps
      version: v1
    path: patch-resource.yaml

images:
  - name: nginx
    newName: my.image.registry/nginx
    newTag: 1.4.0
EOF

mkdir prod
cat <<EOF > prod/kustomization.yaml
#구버전 base 불러오는 방법
bases:
  - ../base
#resources:
#- ../base/kustomization.yaml

namespace: prod-my-nginx

patchesStrategicMerge:
  - patch-replica.yaml

patchesJson6902:
  - target:
      kind: Deployment
      name: my-nginx
      group: apps
      version: v1
    path: patch-resource.yaml

images:
  - name: nginx
    newName: my.image.registry/nginx
    newTag: 1.4.0
EOF

 

추가적으로 patch 파일들을 몇가지 작성하였다.

 

> cd dev
> kubectl kustomize ./

#dev
apiVersion: v1
kind: Service
metadata:
  labels:
    run: my-nginx
  name: my-nginx
  namespace: dev-my-nginx
spec:
  ports:
    - port: 80
      protocol: TCP
  selector:
    run: my-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
  namespace: dev-my-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      run: my-nginx
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
        - image: my.image.registry/nginx:1.4.0
          name: my-nginx
          ports:
            - containerPort: 80
          resources:
            limits:
              memory: 512Mi

> cd ../prod
> kubectl kustomize ./

#prod
apiVersion: v1
kind: Service
metadata:
  labels:
    run: my-nginx
  name: my-nginx
  namespace: prod-my-nginx
spec:
  ports:
    - port: 80
      protocol: TCP
  selector:
    run: my-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
  namespace: prod-my-nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      run: my-nginx
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
        - image: my.image.registry/nginx:1.4.0
          name: my-nginx
          ports:
            - containerPort: 80
          resources:
            limits:
              memory: 1024Mi

 

여기까지 쿠버네티스 설정 파일들을 관리하기 위한 방법으로 kustomize에 대해 간단히 다루어보었다.

posted by 여성게
:
인프라/Docker&Kubernetes 2020. 7. 18. 23:12

 

오늘 다루어볼 포스팅은 "도커 이미지 만들기"이다. 이전에 한번 정리해야지해야지 하면서 미뤄왔었는데, 간단하게 다루어 볼것이다. 필자도 대충은 알았지, 뭔가 깊게 이해하지 못하고 이미지를 빌드했었는데, 이참에 기초부터 한번 정리해봐야겠다.

 

<Dockerfile 작성을 위한 인스트럭션>

 

 

1. FROM : 도커 이미지의 바탕이 될 베이스 이미지를 지정한다. Dockerfile로 이미지를 빌드할 때 먼저 FROM 인스트럭션에 지정된 이미지를 내려받는다. FROM에서 받아오는 도커 이미지는 도커 허브(Docker Hub)라는 레지스트리를 참조한다. 도커 특정 버전 이상에서는 Multi stage build가 가능해져서, 하나의 베이스 이미지(FROM ..)가 아닌 여러 베이스 이미지를 사용하여 빌드가 가능하다(FROM을 여러번 사용)

 

2. RUN : 도커 이미지를 실행할 때 컨테이너 안에서 실행할 명령을 정의하는 인스트럭션이다. 인자로 도커 컨테이너 안에서 실행할 명령을 그대로 기술한다.

 

3. COPY : 도커가 동작 중인 호스트 머신의 파일이나 디렉터리를 도커 컨테이너 안으로 복사하는 인스트럭션이다.

 

4. CMD : 도커 컨테이너를 실행할 때 컨테이너 안에서 실행할 프로세스를 지정한다. 2번의 RUN 인스트럭션은 이미지를 빌드할 때 실행되고, CMD는 컨테이너를 시작할 때 한 번 실행된다.

 

"> go run  /echo/main.go"를 CMD 인스트럭션에 기술하면 아래와 같다.
CMD ["go", "run", "/echo/main.go"]

 

5. ENTRYPOINT : CMD와 마찬가지로 컨테이너 안에서 실행할 프로세스를 지정하는 인스트럭션이다. ENTRYPOINT를 지정하면 CMD의 인자가 ENTRYPOINT에서 실행하는 파일(셸 등)에 인자로 전달된다. 즉, ENTRYPOINT에 지정된 값이 기본 프로세스를 지정하는 것이다.

 

FROM golang:1.10

#./entry.sh을 실행시키면서 ARG1, ARG2를 entry.sh의 인자로 전달한다.
ENTRYPOINT ["./entry.sh"]
CMD ["ARG1", "ARG2"]

 

6. LABEL : 이미지를 만든 사람의 이름 등을 적을 수 있다.

 

7. ENV : 도커 컨테이너 안에서 사용할 수 있는 환경변수를 지정한다.

 

8. ARG : 이미지를 빌드할 때 정보를 함께 넣기 위해 사용한다. 이미지를 빌드할 때만 사용할 수 있는 일시적인 환경변수다.

 

 

posted by 여성게
:
인프라/Docker&Kubernetes 2020. 6. 4. 17:10

이번 포스팅은 간단하게 싱글 노드 카프카를 도커로 띄우는 방법이다.

 

git clone https://github.com/wurstmeister/kafka-docker
cd kafka-docker

 

설정 파일은 docker-compoese로 되어있으며, 아래와 같다.

 

version: '2'
services:
  zookeeper:
    image: wurstmeister/zookeeper
    ports:
      - "2181:2181"
  kafka:
    build: .
    ports:
      - "9092:9092"
    environment:
      KAFKA_ADVERTISED_HOST_NAME: 127.0.0.1
      KAFKA_CREATE_TOPICS: "test:1:1"
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

 

docker compose 명령으로 실제 컨테이너를 띄운다.

 

docker-compose -f docker-compose-single-broker.yml up -d

 

posted by 여성게
:
인프라/Docker&Kubernetes 2020. 4. 21. 11:43

이번 포스팅에서 다루어볼 내용은 DOOD로 도커를 띄웠을 때, proxy 설정하는 방법이다. 그전에 간단하게 Docker in Docker(dind)와 Docker Out Of Dcoker(DooD)에 대해 알아보자.

 

Docker in Docker(dind)

도커 내부에 격리된 Docker 데몬을 실행하는 방법이다. CI(Jenkins docker agent) 측면에서 접근하면 Agent가 Docker client와 Docker Daemon 역할 두가지를 동시에 하게 된다. 하지만 이 방법은 단점이 존재한다. 내부의 도커 컨테이너가 privileged mode로 실행되어야 한다.

 

> docker run --privileged --name dind -d docker:1.8-dind

 

privileged 옵션을 사용하면 모든 장치에 접근할 수 있을뿐만 아니라 호스트 컴퓨터 커널의 대부분의 기능을 사용할 수 있기 때문에 보안에 좋지않은 방법이다. 하지만 실제로 실무에서 많이 쓰는 방법이긴하다.

 

Docker out of Docker(dood)

Docker out of Docker는 호스트 머신에서 동작하고 있는 Docker의 Docker socket과 내부에서 실행되는 Docker socket을 공유하는 방법이다. 간단하게 볼륨을 마운트하여 두 Docker socket을 공유한다.

 

> docker run -v /var/run/docker.sock:/var/run/docker.sock ...

 

이 방식을 그나마 Dind보다는 권장하고 있는 방법이긴하다. 하지만 이 방식도 단점은 존재한다. 내부 도커에서 외부 호스트 도커에서 실행되고 있는 도커 컨테이너를 조회할 수 있고 조작할 수 있기 때문에 보안상 아주 좋다고 이야기할 수는 없다.

 

DooD proxy 설정

dood로 도커를 띄운 경우, 호스트 머신에 동작하고 있는 도커에 proxy 설정이 되어있어야 내부 도커에도 동일한 proxy 설정을 가져간다.

 

방법1. /etc/sysconfig/docker에 프록시 설정
> sudo vi /etc/sysconfig/docker
HTTP_PROXY="http://proxy-domain:port"
HTTPS_PROXY="http://proxy-domain:port"

#docker restart
> service docker restart

 

방법2. 환경변수 설정
> mkdir /etc/systemd/system/docker.service.d
> cd /etc/systemd/system/docker.service.d
> vi http-proxy.conf

[Service]
Environment="HTTP_PROXY=http://proxy-domain:port"
Environment="HTTPS_PROXY=http://proxy-domain:port"
Environment="NO_PROXY=hostname.example.com, 172.10.10.10"

> systemctl daemon-reload
> systemctl restart docker

> systemctl show docker --property Environment
Environment=GOTRACEBACK=crash HTTP_PROXY=http://proxy-domain:port HTTPS_PROXY=http://proxy-domain:port NO_PROXY= hostname.example.com,172.10.10.10

 

여기까지 dood로 도커 엔진을 띄웠을 때, proxy 설정하는 방법이다.

 

 

참고

 

How to configure docker to use proxy – The Geek Diary

 

www.thegeekdiary.com

 

posted by 여성게
:
인프라/Docker&Kubernetes 2020. 4. 20. 21:48

공식 dockerhub가 아닌, 개인 혹은 사내 dockerhub로 push하는 방법이다. (dockerHubHost가 개인 혹은 사내 도커허브 도메인)

 

> docker build -t dockerHubHost/levi.yoon/jenkins_example
> docker push dockerHubHost/levi.yoon/jenkins_example

 

뭔가 다른 방법이 있을 것 같긴한대.. 간단하게 위 방법으로도 가능하다 !

posted by 여성게
:

이번에 다루어볼 포스팅은 도커로 ES를 띄우기전에 뭔가 커스텀한 이미지를 만들어서 올릴수없을까 하는 생각에 간단히 ES 기본 이미지에 한글 형태소 분석기(Nori) 플러그인이 설치가된 ES docker image를 커스텀하게 만들어보았다.

 

#Dockerfile

FROM docker.elastic.co/elasticsearch/elasticsearch:7.6.2

ENV ES_VOLUME=/usr/share/elasticsearch/data
ENV ES_BIN=/usr/share/elasticsearch/bin

RUN mkdir $ES_VOLUME/dictionary
RUN $ES_BIN/elasticsearch-plugin install --batch analysis-nori

 

간단히 설명하면, 베이스 이미지로 공식 elasticsearch image를 사용하였고, 나중에 사용자 사전이 위치할 도커 볼륨 디렉토리를 잡아주었고, 거기에 사전이 담기는 디렉토리를 생성했다. 그리고 마지막으로 한글 형태소분석기 플러그인을 설치하는 쉘을 실행시켰다. 이렇게 빌드된 elasticsearch image는 한글 형태소분석기가 이미 설치가된 elasticsearch image가 된다. 그래서 굳이 plugin directory를 마운트해서 직접 플러그인을 설치할 필요가 없다. 물론 추후에 필요에 의해서 설치해야한다면 어쩔수 없지만 말이다.

 

여기에 추후 더 커스텀할 내용을 넣으면 될듯하다.

posted by 여성게
:
인프라/Docker&Kubernetes 2020. 4. 9. 17:00

 

Dockerfile 파일이 아니라, 커스텀한 파일명으로 docker manifest를 작성하였을 때, 로컬 빌드하는 명령이다. Dockerfile로 작성되어 있을 때 로컬빌드 명령은 아래와 같다.

 

docker build -t 1223yys/web-project:latest .

 

만약 Dockerfile이 아닌 다른 파일명으로 image manifest를 작성하였을 때는 아래와 같다.

 

docker build -t 1223yys/web-project -f ./custom_file_name .

 

위 명령을 실행한 후에 이미지가 잘 빌드되었는지 확인해보자.

 

docker image ls
posted by 여성게
:
인프라/Jenkins 2020. 3. 27. 17:34

 

오늘 다루어볼 포스팅은 Git과 Jenkins를 연동한 이후에 Jenkins Mulibranch pipeline으로 springboot web project를 docker image로 빌드 후 push하는 것까지 다루어볼 것이다. 이전까지는 오늘 다루어볼 포스팅의 연습 및 준비단계였고 본격적으로 CI/CD에 대해 다루어본다. 물론 오늘 다루어볼 포스팅 내용이 실무에서 그대로 활용하기 애매할 수는 있지만 포스팅을 이어나가면서 좀 더 보완해나갈 것이다.

 

1. Git & Jenkins 연동 후 Multibranch pipeline 작성

 

 

Jenkins - CentOS에 docker 환경으로 Jenkins 설치(Jenkins&GitHub CI)

오늘 다루어볼 내용은 CI의 핵심 젠킨스(Jenkins)를 다루어볼 것이다. 사실 이번 포스팅을 시작으로 젠킨스(Jenkins) 관련 몇개의 포스팅이 더 있을 듯하다. 오늘은 간단히 CentOS환경에 docker로 Jenkins를 설치..

coding-start.tistory.com

 

 

Jenkins - Jenkins&GitHub을 이용하여 아주 간단한 MultiBranch pipeline 만들어보기

이전 포스팅에 이어 Jenkins&GitHub을 이용한 CI 실습을 다루어볼 것이다. 이번 포스팅에서는 본격적으로 실습을 진행하기 전에 아주 간단한 echo를 찍어주는 pipeline 하나를 만들어 볼 것이다. 사실 이것을 설..

coding-start.tistory.com

 

위의 내용에 Git & Jenkins 및 간단한 Multibranch pipeline을 연동하는 내용이 있다. 위의 링크를 참조하고, 위에 없는 내용중 보완할 내용만 추가로 다룬다. 젠킨스와 깃의 연동은 크게 다르지 않다. 하지만 Multibranch pipeline 설정이 조금 보완되었다. 

 

1.1. Jenkins Multibranch pipeline 작성

 

General - Display Name과 Description을 작성해준다. (실행에 크게 영향 x)

 

*Branch Sources - 가장 핵심이 되는 configuration 영역이다. Github Credentials와 Repository HTTPS URL을 작성해준다. Credetials는 Jenkins Credentials에서 미리 만들어준다.(github의 인증정보 username/password로 작성하면 된다.) 그리고 깃헙의 https 주소를 넣어준다.

 

 

다음은 push & pull request event를 어떤 branch에 대해 인식시킬지에 대한 설정이다. 그리고 clean after checkout & clean before checkout을 넣어준다.

 

 

master & develop branch에 대해 push&pull request를 인식시키도록 하였다. 추후에는 일반 PR브랜치에 대해 인식시키면 feature branch등도 push&pull request 이벤트로 반응하도록 할 수 있을 것이다.

 

Clean after checkout & Clean before checkout은 .gitignore에 지정된 것을 포함하여 추적되지 않은 모든 파일과 디렉토리를 삭제하여 모든 체크 아웃 전후에 작업 공간을 정리하는 옵션이다.(테스트 결과 등의 파일정리) 또한 소스파일은 업데이트 된 경우 최신 변경사항을 가져오게 된다. Wipe out repository & force clone이라는 비슷한 옵션도 있지만, 이 옵션은 전체 프로젝트 작업 공간을 정리하고 빌드 전에 프로젝트를 다시 한번 클론하기 때문에 시간이 오래 걸린다.(프로젝트가 1기가라면 빌드 할 때마다 1기가를 pull받는다.)

 

 

마지막으로 push&pull request event가 발생시키면 젠킨스는 프로젝트 root에 있는 Jenkinsfile을 기준으로 pipeline을 기동시킨다는 설정이다.

 

2. Dockerfile & Jenkinsfile 작성

Jenkinsfile을 작성하기 전에 docker image build를 위해 우리는 Jenkins을 dood(docker out of docker)로 기동시켜야한다. 만약 준비가 되어 있지 않다면 아래 링크를 참조하자.

 

 

Jenkins - Jenkins dood(docker out of docker)로 실행시켜 agent docker 사용하기

아마 이번 포스팅부터 Jenkins(젠킨스)에서 정말 쓸모 있는 부분을 다룰 것 같다. 젠킨스 파이프라인을 다루기 전에 Jenkins 안에서 dood(docker out of docker)로 docker agent를 실행하는 방법에 대해 다루어..

coding-start.tistory.com

 

그리고 간단히 springboot web project를 생성해준다. 우리는 springboot web을 docker image로 빌드할 것이다.

 

2.1. Dockerfile 작성

간단히 우리가 만든 springboot web image를 빌드하기 위한 Dockerfile을 작성하자.

 

FROM adoptopenjdk/openjdk13:alpine-jre
MAINTAINER levi <1223yys@naver.com>

COPY ./build/libs/jenkins_sample-0.0.1-SNAPSHOT.jar /app/app.jar

EXPOSE 8080
CMD ["java", "-jar", "/app/app.jar"]

 

큰 내용은 없다. openjdk13을 base image로 하여 우리가 빌드한 springboot jar파일을 카피하여 실행시키는 image다.

 

2.2. Jenkinsfile 작성

 

pipeline {
    agent none

    environment {
        SLACK_CHANNEL = '#jenkins_notification'

        REGISTRY = '1223yys/spring-web-jenkins'
        REGISTRYCREDENTIAL = '1223yys'
    }

    stages {
        stage('Start') {
            agent any
            steps {
                slackSend (channel: SLACK_CHANNEL, color: '#FFFF00', message: "STARTED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})")
            }
        }

        stage('Test') {
            agent {
                docker {
                    image 'adoptopenjdk/openjdk13:alpine'
                    alwaysPull true
                }
            }
            steps {
                sh './gradlew test --no-daemon'
            }
        }

        stage('Build') {
            agent {
                docker {
                    image 'adoptopenjdk/openjdk13:alpine'
                    alwaysPull true
                }
            }
            steps {
                sh './gradlew --no-daemon build -x test'
            }
            post {
                success {
                    stash includes: '**/build/**', name: 'build'
                }
            }
        }

        stage('Docker image build & push') {
            agent any
            steps {
                unstash 'build'
                //docker username/password credential
                sh 'docker login -u username -p password'
                sh 'docker build -t $REGISTRY:latest .'
            }
            post {
                success {
                    sh 'docker image ls | grep 1223yys'
                    sh 'docker push $REGISTRY:latest'
                }
            }
        }

        stage('Clean docker image') {
            agent any
            steps {
                sh 'docker rmi $REGISTRY'
            }
        }
    }

    post {
        success {
            slackSend (channel: SLACK_CHANNEL, color: '#00FF00', message: "SUCCESSFUL: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})")
        }
        failure {
            slackSend (channel: SLACK_CHANNEL, color: '#FF0000', message: "FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})")
        }
    }
}

 

파이프라인의 모든 문법을 다루어보지는 못하지만 위에 작성된 문법정도는 다루어볼 것이다. 우선 항상 pipeline {} 가 root에 작성되어야하고 항상 해당 블록내에 파이프라인 스크립트를 작성한다. 그리고 바로 밑에 agent none이 보이는데, pipeline 바로 밑에 agent가 있으면 이것은 글로벌한 agent가 되기 때문에 각 steps마다 다른 agent 사용이 필요할 때는 사용하기 애매하기 때문에 none으로 지정하였다.

 

두번째는 environment {} 이다. 해당 설정에는 사용자 정의 환경설정 작성이 가능하지만 jenkins container 내부에서 사용하는 환경변수가 될수도 있다. 해당 설정은 중요하게 사용될 수 있다. 실제로 필자는 내부망 서버에 젠킨스를 올려 외부 파일을 받는 것이 되지 않아 environment에 proxy설정을 환경변수로 넣어놓아서 외부 파일을 다운로드 받을 수 있게 세팅하였다.

 

세번째는 slack에 파이프라인의 시작을 알림보내는 스크립트이다. 슬랙 알림에 대한 것은 아래 링크를 참고하자. agent any는 현재 젠킨스 인스턴스 중에 하나를 사용하겠다라는 설정이다.

 

 

Jenkins - Jenkins pipeline Slack notification(젠킨스 빌드 슬랙 알림)

오늘 다루어볼 포스팅은 간단하게 젠킨스의 빌드 시작과 성공/실패에 대한 알림을 슬랙으로 받는 방법이다. 간단해서 아주 짧은 포스팅이 될 것 같다. 1. Slack Jenkins CI app install 예제는 이미 슬랙이 설치..

coding-start.tistory.com

 

네번째는 Test stage이다. git에서 checkout 받은 파일중 gradlew를 이용해 테스트 하기 위해서 agent를 openjdk13 base docker image에서 실행하겠다라는 스크립트이다. agent를 docker로 설정하고 사용할 이미지와 image pull 전략을 넣었다. 그리고 해당 docker image(openjdk13) 환경에서 실행할 스크립트를 "./gradlew test --no-daemon"를 작성했다. 참고로 docker agent로 실행시키기 때문에 이 환경은 특정 이미지 컨테이너의 환경이기 때문에 docker 명령이 먹지 않는다. 그 이유는 openjdk container에는 도커 엔진이 없기 때문에 ! 잘 유의하자.

 

 

다섯번째는 Build stage이다. 네번째 테스트 스테이지를 무사히 통과하였다면 이 단계로 넘어온다. 위 테스트 스테이지와 동일한 base 이미지로 build를 수행한다. 하지만 하나 추가된 설정이 있다.

 

post {
   success {
       stash includes: '**/build/**', name: 'build'
   }
}

 

우리는 openjdk13을 볼륨마운트하는 설정을 어디에도 하지 않았고, 해당 이미지는 실행이 끝나면 docker container를 제거시킨다. 그렇기때문에 build된 jar파일이 없어질 것이다. 그래서 위와 같이 특정 파일을 stash(임시 저장)하여 필요할때 꺼내쓰기 위한 설정을 넣어주었다.

 

 

여섯번째는 도커 이미지 build 및 push 스테이지이다. 눈에 띄는 설정이 unstash 'build'이다. 도커 이미지를 빌드하기 위해 jar 파일이 필요하기 때문에 임시저장한 빌드 결과물을 꺼내고 있다. 그리고 해당 파일을 바탕으로 Dockerfile을 사용해 이미지를 빌드한다. agent any로 넣어줬기때문에 우리는 jenkins container로 빌드 잡을 수행한다. 이렇기 때문에 우리는 docker 명령 사용이 가능하다.

 

stage('Docker image build & push') {
    agent any
    steps {
        unstash 'build'
        sh 'ls -al'
        sh 'docker login -u username -p password'
        sh 'docker build -t $REGISTRY:latest .'
    }
    post {
        success {
            sh 'docker image ls | grep 1223yys'
            sh 'docker push $REGISTRY:latest'
        }
    }
}

 

 

마지막 스테이지는 빌드한 이미지를 clean하는 스크립트이다. 이미지를 빌드하면 결국 로컬 디스크에 저장되므로 쌓이기 시작하면 어느샌가 디스크를 많이 먹고 있을 것이다. 그렇기 때문에 매 빌드마다 clean해준다.

 

stage('Clean docker image') {
    agent any
    steps {
        sh 'docker rmi $REGISTRY'
    }
}

 

 

slack에 빌드 성공 메시지가 갔는지 확인해보자.

 

 

마지막으로 dockerhub에 우리가 빌드한 이미지가 잘 올라갔는지 확인하자 !

 

 

오 ! 잘올라갔다 ㅎㅎ 여기까지 간단히 Jenkins Multibranch pipeline을 다루어보았다. 사실 필자는 내부망 장비를 할당받아서 실습했기 때문에 굉장히 삽질을 많이 했다.(외부에서 파일 다운로드 이슈 등) 아마 퍼플릭 존이라면 큰 이슈없이 실습이 가능할 것이다. 혹시나 내부망에서 실습을 진행하다 잘안되는 부분이 있다면 댓글을 남겨주길 바란다.

 

실습한 코드는 아래 깃헙링크를 참고하자.

 

 

yoonyeoseong/jenkins_sample

Contribute to yoonyeoseong/jenkins_sample development by creating an account on GitHub.

github.com

 

posted by 여성게
: