Jenkins을 이용한 파일 준비 자동화(사내 서비스)

Sbae·2024년 7월 23일

현재 k8s 설치 자동화 툴을 개발 중입니다.
아래 본문 중에 script에 NAS upload 과정까지 전부 포함되어있습니다.

기존 파일 준비 과정

실행해야하는 인스턴스의 갯수가 12개... 눈 아파

flash!

  1. terraform을 이용하여 인스턴스 생성
  2. 각각의 인스턴스에 접속 후 shell script를 실행
  3. 이거를 k8s 버전마다 해줘야하니까 12 * (3 or 4) 실행
    • 와 댕 귀찮음

이대로 당할 수 없다

나의 안녕한 눈과 정신 건강을 위해
Jenkins pipeline을 작성하도록 해보자

구조잡기

인스턴스를 생성은 자동화가 되어있으니
각각의 인스턴스에 script를 직접 실행하는 과정을 자동화하자

  1. terraform을 이용한 인스턴스 생성
    1-1. script 파일은 인스턴스 생성할 때 옮기기
  2. Ansible 실행
    2-1. 어라 hosts가 없네?

계획만 완벽했다. 과정이 문제지

hosts 생성

terraform은 무려 json으로 output을 내준다고?
terraform output -json > output.json을 이용해서 json 파일을 생성하고
이거를 파싱하면 되잖아? 완전 럭키비키잖아?

장원영

Parsing 시작!

딸깍딸깍 1분만에 만든 Go파일
파일 읽는 라이브러리 까먹어서 찾지말고 지피티한테 물어볼껄

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"os"
)

// Json parse
type Data struct {
	PrepareNodeIPs       ValueTuple `json:"prepare_node_ips"`
	PrepareNodeOS        ValueTuple `json:"prepare_node_os"`
	PrepareNodePrivateIP ValueTuple `json:"prepare_node_private_ip"`
}

// Type 필드는 배열이라서 interface로 정의
type ValueTuple struct {
	Sensitive bool          	`json:"sensitive"`
	// Type      []interface{} 	`json:"type"`
	Value     []string      	`json:"value"`
}

func main() {
	// JSON 파일 열기
	file, err := os.Open("output.json")
	if err != nil {
		log.Fatalf("파일을 열 수 없습니다: %s", err)
	}
	// 파일을 자동으로 닫아서 메모리 누수 방지
	defer file.Close()

	// 파일 읽기
	byteValue, err := io.ReadAll(file)
	if err != nil {
		log.Fatalf("파일을 읽을 수 없습니다: %s", err)
	}

	// JSON 데이터 파싱
	var data Data
	if err := json.Unmarshal(byteValue, &data); err != nil {
		log.Fatalf("JSON 데이터를 파싱할 수 없습니다: %s", err)
	}

	// hosts 파일 생성
	hostsFile, err := os.Create("./prepare-ansible/inventory/hosts")
	if err != nil {
		log.Fatalf("hosts 파일을 생성할 수 없습니다: %s", err)
	}
	defer hostsFile.Close()

	// hosts 파일 내용을 생성합니다.
	hostsContent := `all:
  hosts:
`
	for i, ip := range data.PrepareNodeIPs.Value {
		hostsContent += fmt.Sprintf("    prepare-%d:\n", i+1)
		hostsContent += fmt.Sprintf("      ansible_host: %s\n", ip)
		hostsContent += "      ansible_port: 22\n"
		hostsContent += "      ansible_user: test\n"
		hostsContent += "      ansible_ssh_private_key_file: ~/.ssh/node-ssh\n"
	}

	// hosts 파일에 내용을 씁니다.
	if _, err := io.WriteString(hostsFile, hostsContent); err != nil {
		fmt.Println("hosts 파일에 내용을 쓰는 데 오류가 발생했습니다:", err)
		return
	}
	fmt.Println("hosts 파일이 성공적으로 생성되었습니다.")
}

이러면 만들어놓은 inventory dir에 hosts라고 생성해준다.

Ansible코드를 작성해볼까?

이 간단한걸 왜 여태 안했지

파일 구조

prepare-ansible
├── inventory
└── playbooks
    ├── prepare.yaml
    └── roles
        └── prepare
            └── tasks
                └── main.yaml

Ansible code

- name: Set custom OS version variable
  ansible.builtin.set_fact:
    os_distribution      : "{{ ('ubuntu' + (ansible_distribution_version | regex_replace('\\.', ''))) if ansible_distribution in ['Ubuntu'] else (ansible_distribution | lower | replace('redhat', 'rhel')) + ansible_distribution_major_version }}"
    os_distribution_arch : "{{ 'amd64' if ansible_architecture == 'x86_64' else 'arm64' if ansible_architecture == 'aarch64' else 'armhf' if ansible_architecture in ['armv6l','armv7l'] else ansible_architecture }}"

- name: Prepare-ansible
  ansible.builtin.shell: "--------쉘 스크립트 실행----------"

Pipeline

jenkins job에서 pipeline 하나만 작성하면 완성!

인스턴스 생성 및 Ansible까지 실행해야해서 간단하게 로직 순서만 작성한다.

  1. 사전 준비
    1-1. tools를 이용해 go, ansible, terraform 사용
    1-2. 환경변수 설정
  2. Git clone
  3. terraform을 이용한 인스턴스 생성
  4. hosts 파일 생성 및 ssh key copy
  5. Ansible playbook 실행

마치며

여태 회사에서 습득한거를 그대로 사용해서 내 눈과 건강을 지켰다.
역시 원인 자체를 제거해버리는게 정답인 것 같다.
유지보수도 내가 해야되네 아 ㅋㅋ

카라짐

profile
끄적이는 일반인

0개의 댓글