AND 조건문 || yaml 앵커

kyoungyeon·2025년 7월 11일
0

TIL

목록 보기
126/129

Syntax 공부

  • 지난 디버깅에 이어서 기억하려고 남겨 놓음
    • AI 답변을 쓰다보니 이모지 많은건 양해부탁드립니다.
    • 매번 쓰던 echo $PATH가 앵커인 것을 이번에 제대로 배워야 겠다 싶어서 공부했습니다.

🔍 && (조건문) vs & (앵커) 비교

1. && - 논리 연산자 (조건문)

# 쉘 스크립트에서 AND 연산자
command1 && command2  # command1이 성공하면 command2 실행
test -f file.txt && echo "파일 존재"

2. & - YAML 앵커 (참조/포인터)

# YAML에서 재사용 가능한 참조 정의
default_config: &default  # &는 앵커 정의
  timeout: 30
  retries: 3

job1:
  <<: *default  # *는 앵커 참조 (포인터처럼 사용)
  
job2:
  <<: *default  # 같은 설정 재사용

상세 비교표

구분&& (논리 연산자)& (YAML 앵커)
용도조건부 실행설정 재사용
개념논리 연산포인터/참조
위치명령어 내부YAML 구조 레벨
문법cmd1 && cmd2&name + *name

🔧 실제 예시로 이해하기

&& 사용 예시 (조건문)

# 성공하면 다음 명령 실행
go build && echo "빌드 성공"

# 실패하면 종료
test -n "$API_KEY" && echo "API Key 존재" || exit 1

# 여러 조건 연결
cd project && make clean && make build && make test

& 앵커 사용 예시 (재사용)

# 공통 설정 정의 (포인터 생성)
.common_script: &common_commands
  - go mod download
  - go build -o app main.go

# 앵커 참조 (포인터 사용)
test_job:
  script:
    - echo "테스트 시작"
    - *common_commands  # 위 설정 재사용
    - go test ./...

deploy_job:
  script:
    - echo "배포 시작"  
    - *common_commands  # 같은 설정 재사용
    - ./app --deploy

🚨 GitLab CI에서 && 문제가 발생한 이유

# ❌ 문제 있던 코드
script:
  - [ -z "$VAR" ] && echo "error" && exit 1

YAML 파서의 착각 과정:
1. &&를 보고 "앵커가 나올 것 같은데?"
2. 하지만 && 뒤에 올바른 앵커 이름이 없음
3. "앵커 문법이 잘못되었다!" → 에러 발생

YAML 앵커는 포인터/참조 개념

# C언어 포인터와 비슷한 개념
# int* ptr = &variable;  (C언어)
# config: &ref_name      (YAML)

database_config: &db_config  # 포인터 정의
  host: localhost
  port: 5432
  timeout: 30

production:
  database: *db_config  # 포인터 역참조

staging: 
  database: *db_config  # 같은 설정 재사용

조건문 &&는 순차 실행

# 프로그래밍의 단락 평가(Short-circuit evaluation)
success() && next_command()  # success가 true여야 next_command 실행
failure() && never_executed()  # failure가 false면 never_executed 실행 안됨

정리

&& (조건문):

  • 쉘 스크립트의 논리 연산자
  • "이것이 성공하면 저것을 실행해"
  • 순차적 실행 제어

& (앵커):

  • YAML의 재사용 메커니즘
  • "이 설정을 여기저기서 재사용하고 싶어"
  • 포인터/참조 개념 (C의 &variable, *pointer와 유사)

GitLab CI 에러의 진짜 원인:

  • &&를 보고 앵커 문법으로 착각
  • 실제로는 단순히 따옴표로 감싸면 해결되는 문제였음
# ✅ 해결된 코드
script:
  - 'test -n "$VAR" && echo "OK" || exit 1'  # 따옴표로 감싸서 문자열로 처리

재질의

  • 착각했던 점

YAML 자체에는 조건문이 없습니다!

# ❌ YAML에는 이런 문법이 없음
if: condition
  then: do_something
  else: do_other

실제로는:

  • &&, ||, ! 등은 쉘 스크립트 문법
  • YAML은 단순히 데이터 구조를 표현하는 언어
  • 조건문은 YAML을 해석하는 도구에서 제공

GitLab CI의 조건문

# GitLab CI에서 제공하는 조건문
rules:
  - if: '$CI_COMMIT_BRANCH == "main"'
  - if: '$CI_PIPELINE_SOURCE == "web"'
  
# GitHub Actions의 조건문  
if: github.ref == 'refs/heads/main'

# Kubernetes의 조건문
when: "{{ .Values.enabled }}"

YAML 앵커의 고급 활용

1. 기본적인 재사용

# 공통 스크립트 정의
.common_setup: &setup
  - apt-get update
  - apt-get install -y curl git
  - go version

.common_cleanup: &cleanup
  - rm -rf /tmp/*
  - docker system prune -f

# 사용
test_job:
  before_script: *setup
  script:
    - go test ./...
  after_script: *cleanup

deploy_job:
  before_script: *setup
  script:
    - go build
    - ./deploy.sh
  after_script: *cleanup

2. 복잡한 설정 병합

# 기본 Docker 설정
.docker_base: &docker_base
  image: golang:1.21
  services:
    - docker:dind
  variables:
    DOCKER_HOST: tcp://docker:2376

# 개발환경 확장
.dev_config: &dev_config
  <<: *docker_base  # 기본 설정 상속
  variables:
    <<: *docker_base.variables  # 변수도 병합
    ENV: development
    DEBUG: "true"

# 운영환경 확장  
.prod_config: &prod_config
  <<: *docker_base
  variables:
    <<: *docker_base.variables
    ENV: production
    DEBUG: "false"

# 실제 job에서 사용
test:
  <<: *dev_config
  script:
    - make test

deploy:
  <<: *prod_config  
  script:
    - make deploy

3. 조건부 설정 (고급)

# 환경별 다른 설정
.database_dev: &db_dev
  host: localhost
  port: 5432
  ssl: false

.database_prod: &db_prod  
  host: prod-db.example.com
  port: 5432
  ssl: true

# 환경에 따라 다른 앵커 참조
development:
  database: *db_dev
  
production:
  database: *db_prod
  • YAML 고도화가 필요한가?

간단한 프로젝트

# 이 정도면 충분
image: golang:1.21
script:
  - go mod download
  - go build
  - go test

복잡한 프로젝트에서는 유용

# 10개 이상의 job이 있는 경우
.go_base: &go_base
  image: golang:1.21
  before_script:
    - go mod download
    - go mod verify
  cache:
    paths:
      - go.sum
      - vendor/

.docker_base: &docker_base
  image: docker:latest
  services:
    - docker:dind
  variables:
    DOCKER_DRIVER: overlay2

# 20개 job에서 재사용...
test_unit: { <<: *go_base, script: ["go test ./..."] }
test_integration: { <<: *go_base, script: ["go test -tags=integration ./..."] }
build_linux: { <<: *go_base, script: ["GOOS=linux go build"] }
build_windows: { <<: *go_base, script: ["GOOS=windows go build"] }
# ... 더 많은 job들

👍 앵커를 사용하면 좋은 경우

  1. 마이크로서비스: 여러 서비스가 비슷한 CI/CD 파이프라인
  2. 멀티 플랫폼 빌드: Linux, Windows, Mac 등
  3. 여러 환경: dev, staging, prod 배포
  4. 대규모 팀: 일관된 설정 유지

👎 과도한 최적화인 경우

  1. job이 5개 미만인 단순한 프로젝트
  2. 설정이 거의 겹치지 않는 경우
  3. 팀이 YAML 앵커에 익숙하지 않은 경우

실용성

왜 앵커가 불필요한가?

  • job이 2개뿐
  • 설정 중복이 최소
  • 복잡도 증가 대비 이익이 적음

앵커가 유용해지는 시점

# 이런 상황이 되면 앵커 고려
.go_common: &go_common
  image: golang:1.21
  before_script:
    - go mod download
    - go vet ./...
    - go fmt ./...

build_linux: { <<: *go_common, script: ["GOOS=linux go build"] }
build_windows: { <<: *go_common, script: ["GOOS=windows go build"] }  
build_darwin: { <<: *go_common, script: ["GOOS=darwin go build"] }
test_unit: { <<: *go_common, script: ["go test ./..."] }
test_race: { <<: *go_common, script: ["go test -race ./..."] }
deploy_dev: { <<: *go_common, script: ["./deploy.sh dev"] }
deploy_prod: { <<: *go_common, script: ["./deploy.sh prod"] }

고려사항:

  • job이 5개 이상 늘어나면 앵커 도입 검토
  • 설정 중복이 눈에 띄기 시작하면 리팩토링
  • 팀이 YAML 앵커에 익숙해지면 점진적 적용

"필요할 때 최적화하라"

profile
🏠TECH & GOSSIP

0개의 댓글