현대 오토에버 SW 스쿨 - 클라우드/버전관리_Jenkins
[Jenkins] - Jenkins 를 이용한 CI/CD
yongyongMom
2024. 11. 12. 17:43
SMALL
1. Docker Image Build & Docker Hub Push
1) Jenkinsfile 에 이미지를 빌드하는 stage 를 추가하고 확인
stage("docker image build"){
steps{
sh 'docker build -t jenkins1112 .'
}
}
- 이미지 빌드가 안되는 경우
- jenkins 에 Docker 관련 Plugin 을 설치
- jenkins 에서 host docker 접근 권한 부여
groupadd -f docker
usermod -aG docker jenkins
chown root:docker /var/run/docker.sock
2) Docker Hub 에 이미지를 푸시하기 위한 준비 작업
- Docker Hub 에서 토큰을 발급받기
- 이미지를 저장하기 위한 Repository 를 생성
- 업로드 되는 도커 이미지는 저장소의 이름과 동일한 이름을 가져야 함
- 토큰을 Jenkins 의 Credential 에 저장
- Jenkins 에 Token 을 직접 사용하면 에러가 발생하고 이후에는 git 에 push 가 안됨
- username And Password 로 등록하는데 Username 에 Docker Hub 의 계정 이름을 설정
- Password 에 토큰 값을 설정
- ID 를 정한 후 ID 를 기억
3) Docker Login
- Jenkinsfile 에 Credential ID 를 변수로 등록
environment{
DOCKERHUB_CREDENTIALS = credentials("docker-hub")
}
- ImageBuild Stage 는 저장소 이름으로 변경하고 로그인 작성
stage("docker image build"){
steps{
sh 'docker build -t ggnagpae1/jenkins1112 .'
}
}
stage('docker hub login'){
steps{
sh 'echo $DOCKERHUB_CREDENTIALS_PSW | docker login -u $DOCKERHUB_CREDENTIALS_USR --password-stdin'
}
}
4) Docker Image Push
- stage 에 추가
steps{
sh 'docker push ggnagpae1/jenkins1112:latest'
}
}
2. Jenkins 가 제공하는 환경 변수
- env.VARNAME 으로 사용이 가능 -> 전역변수
- env 가 제공되는 변수
BUILD_ID
JOB_NAME
CHANGE_ID
CHANGE_URL
CHANGE_TARGET
CHANGE_BRANCH
BUILD_NUMBER
JENKINS_URL
BUILD_URL
JOB_URL
- currentBuild 라는 환경 변수는 현재 빌드에만 해당되는 지역변수
- number
- result
- currentResult
- duration
- keepLong
- displayName
3. 배포
1) Jenkins 에 컨테이너를 만드는 코드를 추가
stage('deploy'){
steps{
sh "docker run -d --rm -p 8765:8080 --name jenkins1112 ggnagpae1/jenkins1112"
}
}
2) 인수 테스트
- 루트 디렉터리에 스크립트 파일 생성 : acceptance_test.sh
#!/bin/bash
test $(curl localhost:8765?a=1\&b=2) -eq 2
- 스크립트 파일을 실행하는 코드를 스테이지에 추가
- sleep 을 사용하는 이유
- docker run -d 가 비동기 방식으로 실행 -> 연속 테스트 명령 -> 컨테이너 만들기전 명령 실행
- 실행은 정상적이나 테스트 단계에서 실패로 판정하는 경우 발생 가능
stage('acceptance test'){
steps{
sleep 60
sh 'chmod +x acceptance_test.sh && ./acceptance_test.sh'
}
}
3) clean up 스테이지 추가
post{
always{
sh 'docker stop jenkins1112'
}
}
4. 인수 테스트 작성
1) 개요
- 웹 애플리케이션의 경우 curl 명령을 이용해서 인수 테스트 가능
- 기술적 측면만 보면 REST 웹 서비스를 작성한 경우 curl 호출 방식으로 모든 블랙박스 테스트 구성 가능
- 블랙박스 테스트 : 사용자의 요구 사항에 맞게 동작하는지 기능을 테스트
- 모든 경우를 전부 테스트, 경계값 분석을 해주는 것이 중요함
- curl 명령으로 테스트를 하는 것은 읽고 이해하기가 어려움, 유지보수에도 좋지 않음
2) 사용자-대면 테스트 작성
- 대부분의 소프트웨어가 특정한 목적을 가지고 개발되며 대부분은 개발자가 아닌 일반 사용자에게 서비스를 제공
- 사용자가 인수 기준을 정해야 하며 이를 가지고 자동 인수 테스트를 수행하도록 해주어야 함
- 프레임워크 : 큐컴버, 피트니스, JBehave 등이 있음
- 사용자가 인수 기준을 정함
- 개발자가 픽스쳐와 스텝을 정의
- 자동 인수 테스트 수행
- 인수 기준을 시나리오 형태로 작성
Given I have two numbers: 1 and 3
When the calculator sums them
Then I receive 3 as a result
- 개발자는 픽스쳐 또는 스텝 정의라고 부르는 사용자 친화적인 도메인 특화 언어(DSL) 와 프로그래밍 언어와 통합해서 테스트 작성
3) cucumber
- build.gradle 파일의 dependencies 에 의존성 라이브러리를 추가
testImplementation("io.cucumber:cucumber-java:7.2.0")
testImplementation("io.cucumber:cucumber-junit:7.2.0")
- src/test/resource/feature 디렉터리에 calculator.feature 파일을 만들고 시나리오 작성
Feature: Calculator
Scenario: Sum two numbers
Given I have two numbers: 1 and 2
When the calculator sums them
Then I receive 2 as result
- 기능 사양을 실행할 수 있는 자바 바인딩을 생성
src/test/java/acceptance/StepDefinitions.java 파일로 생성
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import org.springframework.web.client.RestTemplate;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class StepDefinitions {
//서버 URL을 저장
private String server = System.getProperty("calculator.url");
//웹 서비스 요청을 위한 클래스
private RestTemplate restTemplate = new RestTemplate();
//매개변수 와 결과를 저장할 변수
private String a;
private String b;
private String result;
@Given("^I have two numbers: (.*) and (.*)$")
public void i_have_two_numbers(String a, String b) throws Throwable {
this.a = a;
this.b = b;
}
@When("^the calculator sums them$")
public void the_calculator_sums_them() throws Throwable{
String url = String.format("%s?a=%s&%b=%s", server, a, b);
result = restTemplate.getForObject(url, String.class);
}
@Then("^I recevie (.*) as a result")
public void i_receive_as_a_result(String expectedResult) throws Throwable{
assertEquals(expectedResult, result);
}
}
- build.gradel 파일에 코드를 작성
tasks.register('acceptanceTest', Test){
include '**/acceptance/**'
systemProperties System.getProperties()
}
test{
exclude '**/acceptance/**'
}
- src/test/java/acceptance 패키지에 JUnit 테스트
러너(AcceptanceTest) 추가
package acceptance;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;
@RunWith(Cucumber.class)
@CucumberOptions(features = "classpath:feature")
public class AcceptanceTest {
}
- 테스트 명령
./gradlew acceptanceTest -Dcalculator.url=http://54.180.146.200:8765
5. Kubenetes
1) 쿠버네티스에 업로드한 이미지를 파드로 배포
- deployment.yaml 파일을 생성하고 작성
apiVersion: apps/v1 #API 버전은 apps/v1(batch/v1, v1)
kind: Deployment #리소스 종류
#부가 정보를 설정
metadata:
name: calculator-deployment
labels:
app: calculator
spec:
#동일한 이미지로 만든 파드가 3개
replicas: 3
#Deployment가 관리할 파드를 찾는 방법
#레이블로 찾는데 그 이름은 app: calculator
selector:
matchLabels:
app: calculator
#생성될 파드의 사양
template:
#파드의 이름 설정
metadata:
labels:
app: calculator
#각 파드가 containerd 나 docker에서 만들어질 때 컨테이너 이름 과 이미지 그리고 외부에 공개할 포트 번호
spec:
containers:
- name: calculator
image: ggnagpae1/jenkins1112
ports:
- containerPort: 8080
- yaml 파일 실행
kubectl apply -f deployment.yaml
- 파드 확인
kubectl get pods
- 로그 확인
kubectl logs pods/파드의이름
- kubectl 명령 확인
https://kubernetes.io/docs/reference/kubectl/
2) 서비스
- 개요
- 사용자 -> Service -> Pod 를 선택해서 요청을 전송
- service.yml 파일을 생성하고 작성
apiVersion: v1
kind: Service
metadata:
name: calculator-service
spec:
type: NodePort
selector:
app: calculator
ports:
- port: 8080
- 서비스 실행
kubectl apply -f service.yml
- 서비스 확인
kubectl get svc
kubectl describe scv 서비스이름
- 애플리케이션 노출 : type
- ClusterIP
- : 기본 설정값으로 서비스는 내부 IP 만 소유
- NodePort
- 클러스터 노드마다 동일한 포트를 갖도록 서비스를 노출
- 물리적 기기 (노드) 는 서비스로 전달되는 포트를 오픈 시 다른노드에서 <노드-IP>:<노드포트>로 접근하는 것이 가능
- LoadBalancer
- 외부 로드 밸런서를 생성한 후 서비스에 별도의 외부 IP 를 할당하는 것
- 클러스터를 외부로 노출해서 접근이 가능하도록 하는 것
- Ingress
- 클러스터 외부에서 클러스터 내부 서비스로 HTTP 와 HTTPS 경로를 노출
- 외부에 로드 밸런서를 배치 -> 아넹 ingress 배치
- 사용자 -> ingress managed LoadBalancer -> ingress -> 서비스
- ExternalName
- 외부 URL 을 내부에서 다른 이름으로 접근할 수 있도록 하는 것
- ClusterIP
3) 파드의 업데이트 전략
- Deployment 를 만들 때 spec 항목에 strategy 의 type 에 설정
- 기본은 RollingUpdate
- 순서대로 하나를 생성하고 정상 동작하면 새로운 하나를 만들면서 과거의 하나를 삭제해 나가는 방식
4) 캐시 전략
- 컨테이너를 사용하게 되면 컨테이너를 사용하지 않은 경우보다 응답 속도가 느리게 됨
- 자주 사용하는 메서드에 cache 기능을 부여해 동일한 호출의 경우는 캐시에서 응답하도록 설정하는 것이 좋음
반응형
LIST