예전에 했던 서버 구축글에서 docker swam을 쿠버네티스로 바꾸던 걸 정리했던 글입니다.
1. 젠킨스에서 도커 빌드 가능하게 설정하기
기존에 Docker Compose로 구성해서 서버에서 바로 docker 이미지를 만들었다면 이번에는 Jenkins에서 빌드를 해서 이미지를 생성하고 해당 이미지를 넥서스에 올린 후 각각의 서버에서 해당 이미지를 사용방식으로 만들려고 합니다.
가장 먼저 젠킨스에서 도커를 빌드하고 빌드된 이미지를 사내 dockerhub(Nexus)에 올릴 수 있게 해주어야 합니다.
도커로 구동된 젠킨스에서 도커를 실행하려면 docker.sock 파일을 볼륨해줘야 합니다.
sudo docker run -d -p 8080:8080 -v /home/jenkins:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock
1.1 젠킨스 백업하기
만약 기존에 사용하던 젠킨스가 있다면 해당 젠킨스에 workspace폴더를 복사해 놓은 후에 새로 설치된 젠킨스에 덮어 씌우시면 됩니다.
2. 쿠버네티스 설정 사전작업
2.1 React 빌드 및 도커 이미지 만들기
먼저 프론트쪽 배포를 위해서 리액트 빌드를 해야 합니다. 그런데 이번에는 테스트 서버에만 배포하는 게 아닌 테스트와 실섭 두개로 구분을 해서 배포를 해야 하기 때문에 배포 설정을 해주어야 합니다. 그리고 빌드된 React파일은 Nginx 아래에서 실행이 됩니다.
또한 도커 이미지를 만들 때 빌드된 (build) 폴더가 실행되는 Nginx 서버에 설정을 위해 default.conf 설정파일을 미리 프로젝트 안에 준비를 해놓습니다. 그리고 Dockerfile에 실행될 도커이미지의 설정을 작성합니다.
- 서버에 따른 빌드 스크립트 package.json에 설정하기
"scripts": {
.
.
"build-test": "env-cmd -f .env.test react-scripts build",
"build-dev": "env-cmd -f .env.dev react-scripts build",
"build-prod": "env-cmd -f .env.prod react-scripts build",
.
.
},
- nginx 설정파일 만들기: conf/conf.d/default.conf 파일 만들기
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
- Dockerfile 만들기
FROM nginx:1.13.9-alpine
EXPOSE 80
RUN rm -rf /etc/nginx/conf.d
COPY ./conf /etc/nginx
COPY ./build /usr/share/nginx/html
CMD ["nginx", "-g", "daemon off;"]
Nginx를 기반으로 설정한 conf폴더와 빌드된 React폴더를 복사해 이미지 안에 넣고 Nginx를 시작한다.
2.2 Java 빌드 및 도커 이미지 만들기
자바 프로젝트를 Maven으로 빌드를 해서 도커이미지를 만들고 실행을 시킨다.
빌드
mvn clean install -Dmaven.test.skip=true -Pprod
기존에 빌드되어 있던 파일을 지우고 빌드를 한다. 옵션으로는 테스트를 Skip하는 옵션과 프로파일을 설정했다.
Dockerfile
FROM openjdk:14-slim
EXPOSE 8081
ADD ./target/*.jar vc.jar
ENTRYPOINT ["java","-jar","/vc.jar"]
오픈 JDK를 기반으로 각각의 프로젝트에 맞는 포트를 열어주고 빌드된 jar파일을 복사해서 이미지에 넣은 후 실행을 한다.
3. 쿠버네티스 설정하기
쿠버네티스를 AWS에서 설치해서 사용할 생각이며 사용할 툴로는 Kops를 사용할 생각이다.
3.1 kops 설치하기
먼저 kops를 사용할 인스턴스(CI서버)에 kops를 설치한다. 설치에 관련된 내용은 https://kops.sigs.k8s.io/getting_started/install/ 이 사이트에 자세히 나와있다.
일단 회사 CI 서버에 경우 우분투로 구성되어 있어서 리눅스 설치 명령어를 복사해서 실행시킨다.
curl -LO https://github.com/kubernetes/kops/releases/download/$(curl -s https://api.github.com/repos/kubernetes/kops/releases/latest | grep tag_name | cut -d '"' -f 4)/kops-linux-amd64
chmod +x kops-linux-amd64
sudo mv kops-linux-amd64 /usr/local/bin/kops
3.2 AWS IAM 설정
AWS에서 IAM을 하나 설정한다. 필요한 권한으로는 아래 5가지 권한을 설정해 주면 된다.
- AmazonEC2FullAccess
- AmazonRoute53FullAccess
- AmazonS3FullAccess
- IAMFullAccess
- AmazonVPCFullAccess
3.3 AWS CLI 설치&설정
기존에 설치된 AWSCLI가 없다면 설치를 해준다.
apt install awscli # awscli 설치
# aws 설정
aws configure
Access Key: [입력]
Secret Access Key: [입력]
Default region name: ap-northeast-2 # 한국 1은 일본
Default output format: [엔터]
3.3 route53 설정
쿠버네티스 클러스터 정보가 저장될 S3 저장소를 하나 생성한다. 그리고 버킷에 버저닝을 기록하도록 설정한다.
aws s3api create-bucket --bucket [버킷이름] --create-bucket-configuration LocationConstraint=ap-northeast-1
aws s3api put-bucket-versioning --bucket [버킷이름] --versioning-configuration Status=Enabled
3.4 ssh-key 설정
ssh-keygen -t rsa -N "" -f ./id_rsa
3.5 쿠버네티스 클러스터 생성하기
kops create cluster --state [s3:저장소이름] --zones ap-northeast-1a - -networking calico --ssh-public-key ./id_rsa.pub [도메인 이름]
3.6 노드 설정
kops edit ig master-ap-northeast-1a --name [도메인 이름] --state [s3:저장소이름] # 마스터 노드 설정
kops edit ig nodes --name [도메인 이름] --state [s3:저장소이름] # 노드 설정\
3.7 쿠버네티스 클러스터 생성하기
kops update cluster --yes [도메인 이름] # 클러스터 생성하기
kops validate cluster --state [s3:저장소이름] # 진행사항 확인하기
3.3 쿠버네티스에 private docker hub 설정하기
사내에 Docker Hub가 구축되어 있다면 해당 저장소에 이미지를 가져올 수 있게 설정을 해주어야 한다.
kubectl create secret docker-registry [시크릿 이름]
--docker-server=[사내 저장소 주소]
--docker-username=[유저 이름]
--docker-password=[비밀번호]
--docker-email=[이메일]
그리고 CI 서버에서 사내 Docker Hub에 이미지를 올려야 하기 때문에 저장소 설정을 해준다.
sudo vi /etc/docker/daemon.json
{
"insecure-registries": ["저장소 주소"]
}
마지막으로 쿠버네티스 pod을 만드는 설정안에 사내 저장소에 접근할 수 있게 설정을 추가한다.
imagePullSecrets:
- name: [설정된 시크릿 이름]
3.4 health 설정
쿠버네티스에 이미지가 배포 되었을 때 잘 실행이이 되었는 지 그리고 실행 중에 정지가 되지 않았는 지 확인을 하기 위한 설정을 해야합니다. Spring에 Actuator을 설정했고 쿠버네티스 설정파일에 해당 내용 관련 코드를 추가해준다.
livenessProbe:
httpGet:
path: /actuator/info
port: 80
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 10
successThreshold: 1
readinessProbe:
httpGet:
scheme: HTTP
path: /actuator/health
port: 80
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
successThreshold: 1
3.5 aws 로드밸런서&인증서 설정
외부에서 접근할 수 있게 쿠버네티스 서비스를 설정을 한다.
실서버에 배포되는 프로젝트에 경우 https을 설정해 주어야 하기 때문에 443포트를 열고 aws에서 제공하는 인증서를 등록 후에 인증서 정보를 입력한다.
apiVersion: v1
kind: Service
metadata:
name: [서비스 이름]
namespace: [namespace 이름]
annotations:
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: [보안 인증서]
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: https
spec:
type: LoadBalancer
selector:
app: [프로젝트 이름]
ports:
- name: http
port: 80
targetPort: 80
- name: https
port: 443
targetPort: 80
4. 젠킨스에서 배포 설정하기
자바 프로젝트의 경우 프로젝트를 빌드를 하고 빌드한 파일을 바탕으로 도커이미지 파일을 생성한다.
생성된 도커이미지파일을 사내 Docker-Hub에 올리고 쿠버네티스 노드로 배포한다.
올라가는 버전의 경우에는 따로 파라미터로 받아 설정한다.
#!/bin/bash
mvn clean install -Dmaven.test.skip=true -Pdev
docker build --tag docker.effectmall.com/startup-dev:v1.${major}.${minor} ./
docker push docker.effectmall.com/startup-dev:v1.${major}.${minor}
kubectl set image deployment startup startup-con=docker.effectmall.com/startup-dev:v1.${major}.${minor} --record --namespace=invest-dev
5. 일래스틱 서치 설정해서 로그 가져오기
filebeat를 사용해서 일래스틱에 로그를 가져올 수 있게 한다.
아래 내용에 일래스틱 호스트 주소와 아이디 비밀번호를 설정해서 쿠버네티스에 등록한다.
---
apiVersion: v1
kind: ConfigMap
metadata:
name: filebeat-config
namespace: default
labels:
k8s-app: filebeat
data:
filebeat.yml: |-
filebeat.inputs:
- type: container
paths:
- /var/log/containers/*.log
processors:
- add_kubernetes_metadata:
host: ${NODE_NAME}
matchers:
- logs_path:
logs_path: "/var/log/containers/"
processors:
- add_cloud_metadata:
- add_host_metadata:
cloud.id: ${ELASTIC_CLOUD_ID}
cloud.auth: ${ELASTIC_CLOUD_AUTH}
output.elasticsearch:
hosts: ['${ELASTICSEARCH_HOST:elasticsearch}:${ELASTICSEARCH_PORT:9200}']
username: ${ELASTICSEARCH_USERNAME}
password: ${ELASTICSEARCH_PASSWORD}
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: filebeat
namespace: default
labels:
k8s-app: filebeat
spec:
selector:
matchLabels:
k8s-app: filebeat
template:
metadata:
labels:
k8s-app: filebeat
spec:
serviceAccountName: filebeat
terminationGracePeriodSeconds: 30
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
containers:
- name: filebeat
image: docker.elastic.co/beats/filebeat:7.5.2
args: [
"-c", "/etc/filebeat.yml",
"-e",
]
env:
- name: ELASTICSEARCH_HOST
value: [일래스틱 호스트 주소]
- name: ELASTICSEARCH_PORT
value: "9200"
- name: ELASTICSEARCH_USERNAME
value: elastic
- name: ELASTICSEARCH_PASSWORD
value: [비밀번호]
- name: ELASTIC_CLOUD_ID
value:
- name: ELASTIC_CLOUD_AUTH
value:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
securityContext:
runAsUser: 0
# If using Red Hat OpenShift uncomment this:
#privileged: true
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 100Mi
volumeMounts:
- name: config
mountPath: /etc/filebeat.yml
readOnly: true
subPath: filebeat.yml
- name: data
mountPath: /usr/share/filebeat/data
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
- name: varlog
mountPath: /var/log
readOnly: true
volumes:
- name: config
configMap:
defaultMode: 0600
name: filebeat-config
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- name: varlog
hostPath:
path: /var/log
# data folder stores a registry of read status for all files, so we don't send everything again on a Filebeat pod restart
- name: data
hostPath:
path: /var/lib/filebeat-data
type: DirectoryOrCreate
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: filebeat
subjects:
- kind: ServiceAccount
name: filebeat
namespace: default
roleRef:
kind: ClusterRole
name: filebeat
apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: filebeat
labels:
k8s-app: filebeat
rules:
- apiGroups: [""] # "" indicates the core API group
resources:
- namespaces
- pods
verbs:
- get
- watch
- list
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: filebeat
namespace: default
labels:
k8s-app: filebeat
---
'정리' 카테고리의 다른 글
PostgreSQL에서다중 속성 값 처리(Array) (0) | 2022.11.12 |
---|
댓글