Amazon Linux Crontab Install

✅ 1. cronie 패키지 설치

crontab 명령어는 cronie 패키지에 포함되어 있습니다. 아래 명령으로 설치하세요.

sudo yum install cronie -y

✅ 2. crond 데몬 활성화 및 실행

설치 후에는 crond 서비스(크론 데몬)를 활성화하고 실행해야 합니다.

sudo systemctl enable crond
sudo systemctl start crond

systemctl status crond

✅ 3. 사용자별 crontab 편집

설치 및 실행이 완료되면 다음 명령으로 사용자 크론 설정을 할 수 있습니다.

crontab -e


예시: 매일 5시에 쉘 스크립트를 실행

0 5 * * * /home/ec2-user/backup.sh >> /home/ec2-user/backup.log 2>&1

🔍 참고: 크론 로그 확인

Amazon Linux에서는 기본적으로 /var/log/cron 파일에 로그가 남습니다.

sudo tail -f /var/log/cron

Crontab 사용방법

✅ crontab 기본 명령어

명령어설명
crontab -e현재 사용자에 대한 크론 편집
crontab -l등록된 크론 작업 목록 확인
crontab -r현재 사용자의 크론 작업 전체 삭제
crontab -u [USER] -e특정 사용자의 크론 편집 (root만 가능)

⏰ crontab 시간 형식

scss복사편집* * * * *  명령어
│ │ │ │ │
│ │ │ │ └─ 요일 (0~7) (0과 7은 일요일)
│ │ │ └─── 월 (1~12)
│ │ └───── 일 (1~31)
│ └─────── 시 (0~23)
└───────── 분 (0~59)

예시:

스케줄의미
0 3 * * *매일 새벽 3시에 실행
*/10 * * * *10분마다 실행
0 9-17 * * 1-5평일 오전 9시부터 오후 5시까지 매시 정각 실행
0 0 1 * *매달 1일 0시에 실행
0 22 * * 0매주 일요일 밤 10시에 실행

📂 로그 확인

기본적으로 크론 작업은 시스템 로그에 기록됩니다:

  • Ubuntu: /var/log/syslog
  • CentOS/RHEL: /var/log/cron

예:

grep CRON /var/log/syslog

⚠️ 주의사항

  1. 환경 변수 차이: crontab은 로그인 쉘이 아니므로 PATH가 다를 수 있음.
    • 명령어 앞에 전체 경로 사용 권장 (예: /usr/bin/python3 등)
    • 또는 스크립트에 #!/bin/bashexport PATH=... 명시
  2. 출력 리디렉션: 오류나 출력을 파일로 저장하려면 다음과 같이 설정:
* * * * * /path/to/script.sh >> /path/to/logfile.log 2>&1
  1. 권한 확인: 실행하려는 스크립트는 실행 권한이 있어야 함 (chmod +x script.sh)

🎯 실용 예시

  1. 매일 1시에 백업 실행
0 1 * * * /home/user/backup.sh
  1. 매 5분마다 웹서버 확인
*/5 * * * * curl -fs http://localhost:80 || systemctl restart nginx
  1. Python 스크립트 실행
0 0 * * * /usr/bin/python3 /home/user/script.py

NVIDIA 드라이버 버전 불일치

NVRM: API mismatch: the client has the version 570.124.06, but
NVRM: this kernel module has the version 550.144.03.  Please
NVRM: make sure that this kernel module and all NVIDIA driver
NVRM: components have the same version.

원인 설명

  • NVIDIA 커널 모듈(Driver)사용 중인 NVIDIA 라이브러리(Client) 의 버전이 다릅니다.
    • 커널 모듈 버전: 550.144.03
    • 클라이언트(라이브러리) 버전: 570.124.06

상황 예시

  • OS 부팅 시, 커널 모듈(예: /lib/modules/$(uname -r)/kernel/drivers/video/nvidia.ko)이 550 버전임.
  • 유저가 CUDA, cuDNN, pytorch, nvidia-docker 등에서 사용하는 nvidia-smi, libcuda.so 같은 사용자 공간 라이브러리는 570 버전임.
  • 이럴 때, NVIDIA 드라이버는 항상 버전이 동일해야 하고, 다르면 GPU가 정상 동작하지 않거나 CUDA가 인식되지 않습니다.

주로 발생하는 원인

  1. NVIDIA 드라이버 업그레이드/다운그레이드 후 재부팅 없이 사용
  2. apt/yum 등으로 패키지 설치/업데이트 후 옛날 커널 모듈이 남아 있음
  3. NVIDIA Docker, CUDA Toolkit, cuDNN, Pytorch 등 개별 설치 시 충돌
  4. 커널 업데이트 후 드라이버 재설치 안 함

해결 방법

  1. 드라이버 완전히 재설치 (추천)
    • 기존 드라이버 완전히 삭제
sudo nvidia-uninstall
sudo apt-get remove --purge nvidia-*
sudo yum remove nvidia-*
  • 모든 커널 모듈 및 라이브러리 삭제
sudo rm -rf /usr/local/cuda*
sudo rm -rf /lib/modules/$(uname -r)/kernel/drivers/video/nvidia*
sudo rm -rf /usr/lib/x86_64-linux-gnu/libnvidia*
  • 서버 재부팅
sudo reboot
# Ubuntu 예시
sudo apt-get update
sudo apt-get install nvidia-driver-570
  1. 설치 후 꼭 재부팅
sudo reboot
  1. 버전 확인
nvidia-smi
# Driver Version이 570.124.06 처럼 나와야 함


추가로 현재 설치된 드라이버/라이브러리 상태 확인 명령어:

nvidia-smi
cat /proc/driver/nvidia/version
lsmod | grep nvidia

gitlab 복원 방법

한 GitLab 인스턴스에서 만든 백업 파일을 다른 GitLab 서버에 복원(추가)할 수 있습니다.

다만 다음 조건과 제약이 있습니다.

버전 일치
복원할 대상 서버의 GitLab 패키지 버전이 백업을 만든 서버와 동일해야 합니다. 버전이 다르면 데이터베이스 구조가 달라져 복원에 실패하거나 손상될 수 있습니다.

전체 복원 방식
GitLab의 gitlab-backup은 “전체 인스턴스” 단위 백업/복원만 지원합니다. 즉, 한 서버에서 A 프로젝트만, B 프로젝트만 골라서 복원하거나 두 개의 백업을 병합해서 복원하는 기능은 없습니다.

  • 만약 특정 프로젝트만 옮기고 싶다면, 프로젝트 내보내기/가져오기(export/import) 기능을 쓰셔야 합니다.

전체 백업 복원 절차

아래 예시는 Omnibus 패키지(GitLab CE/EE) 환경을 기준으로 합니다.

  1. 백업 파일 복사
    • 원본 서버에서 /var/opt/gitlab/backups/ 디렉터리에 있는 TIMESTAMP_gitlab_backup.tar 파일을 대상 서버로 복사
scp /var/opt/gitlab/backups/1612345678_2025_04_22_14.0.0_gitlab_backup.tar root@new-server:/var/opt/gitlab/backups/
  1. 대상 서버 버전 확인 및 재설치
    • 대상 서버에 원본 서버와 동일한 GitLab 버전을 설치
# 예: GitLab EE 14.0.0 설치
curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.deb.sh | sudo bash
sudo EXTERNAL_URL="https://gitlab.example.com" apt-get install gitlab-ee=14.0.0-ee.0
  1. GitLab 서비스 중지
sudo gitlab-ctl stop unicorn
sudo gitlab-ctl stop sidekiq
sudo gitlab-ctl stop nginx
  1. 백업 복원 명령 실행
    • 복원 도중 데이터베이스 스키마 및 레디스 캐시가 덮어씌워집니다.
    • 복원 시 /etc/gitlab/gitlab.rb 설정은 보존되므로, 필요한 경우 미리 SSH 키, 레포지토리 경로, TLS 인증서 등을 확인해 두세요.
# 기본적으로 가장 최신 백업 파일을 복원합니다.
sudo gitlab-backup restore BACKUP=1612345678_2025_04_22_14.0.0
  1. 권한 및 설정 재적용
    복원이 끝나면
sudo gitlab-ctl reconfigure
sudo gitlab-ctl restart

명령으로 설정을 재적용하고 서비스를 재시작합니다.

  1. 접근 테스트
    • 웹 브라우저로 접속해 프로젝트, 사용자, 그룹, CI/CD 파이프라인 등이 정상 동작하는지 확인합니다.

프로젝트 단위 데이터 이동 방법

  • 프로젝트 Export/Import
    • 프로젝트 단위로 이동하고 싶다면, 원본 서버에서 프로젝트 설정 → “Export project”
    • 내보낸 .tar.gz 파일을 대상 서버 프로젝트 생성 화면에서 “Import project”
    • 이 경우에는 백업 전체를 덮어쓰지 않고 특정 프로젝트만 선택적으로 가져올 수 있습니다.

요약

  • 가능: 전체 인스턴스 백업 → 다른 동일 버전 서버에 복원
  • 불가능: 서로 다른 백업을 합쳐서 복원하거나, A 백업 + B 백업 데이터 병합
  • 대안: 특정 프로젝트만 옮길 땐 GitLab의 Export/Import 기능 사용

이 절차대로 진행하시면 다른 GitLab 서버에 문제없이 백업 데이터를 복원하실 수 있습니다.

Hyper-V Ubuntu 플로피 오류

blk_update_request: I/O error, dev fd0, sector 0 op 0x0:(READ) flags 0x80700 phys_seg 1 prio class 0
Buffer I/O error on dev fd0, logical block 0, async page read

이 문제는 일반적으로 Ubuntu가 부팅 과정에서 가상 환경에서 제공하지 않는 플로피 디스크를 검색하려고 시도할 때 발생합니다.

해결 방법:

Hyper-V에서 아래 방법으로 해결할 수 있습니다.

  1. Ubuntu 가상머신 설정 변경
    • Hyper-V 관리자에서 가상 머신을 종료하고 설정(Settings) 메뉴로 이동합니다.
    • 하드웨어(Hardware) 섹션에서 플로피 디스크(Floppy Drive) 항목을 제거합니다.
    • 변경 사항을 적용한 후 다시 부팅합니다.
  2. Ubuntu에서 플로피 디스크 모듈 비활성화
    플로피 디스크를 사용하지 않을 경우 아예 시스템 모듈에서 비활성화하는 것이 좋습니다. 터미널에서 다음 명령어로 플로피 모듈을 비활성화할 수 있습니다.
sudo rmmod floppy
echo "blacklist floppy" | sudo tee /etc/modprobe.d/blacklist-floppy.conf
sudo update-initramfs -u
sudo reboot

Kotlin 장점

1. 구글 공식 지원 및 생태계 연계

  • 안드로이드 공식 언어
    2017년 구글이 안드로이드 공식 언어로 코틀린을 채택하면서, 최신 안드로이드 API / 라이브러리와의 호환성 및 우선 지원을 보장합니다.
  • 강력한 생태계
    JetBrains, Google, AWS, Spring 등 주요 플랫폼·프레임워크에서 코틀린을 적극 활용하고 있어, 풍부한 문서와 샘플 코드, 커뮤니티 지원을 받을 수 있습니다.

2. 간결하고 가독성 높은 문법

  • 타입 추론(type inference)
    val name: String = "Alice" 대신 val name = "Alice" 만으로 충분합니다.
  • 데이터 클래스(data class)
    보일러플레이트 없이 equals(), hashCode(), toString() 등을 자동 생성해 줍니다.
data class User(val id: Int, val name: String)

확장 함수(extension functions)
기존 클래스의 코드를 수정하지 않고 원하는 메서드를 추가할 수 있어 유연합니다.

fun String.capitalizeWords() = split(" ").joinToString(" ") { it.capitalize() }

3. Null 안전성(null-safety)

  • 컴파일 타임 체크
    애매한 널 처리로 인한 NullPointerException을 대폭 줄여 줍니다.
var s: String? = null
println(s?.length ?: 0)  // 안전하게 널 처리
  • 명시적 널 허용
    변수 타입에 ?를 붙여야만 널을 담을 수 있어, 코드 읽기만으로도 어디서 널을 주의해야 할지 한눈에 파악할 수 있습니다.

4. 코루틴(Coroutines)을 통한 비동기 처리

  • 경량 스레드
    코루틴은 스레드보다 훨씬 가볍고, 수천 개의 동시 작업도 부담 없이 처리합니다.
  • 직관적인 비동기 코드
    suspend 함수와 launch·async 빌더를 사용해 동기 코드처럼 작성할 수 있어 가독성이 뛰어납니다.
suspend fun fetchData(): String { /* ... */ }

GlobalScope.launch {
    val data = async { fetchData() }
    println("결과: ${data.await()}")
}

5. 자바(Java)와 100% 상호 운용성

  • 기존 자바 코드 재사용
    프로젝트에 코틀린 파일을 추가해도, 자바 라이브러리·프레임워크를 그대로 호출할 수 있습니다.
  • 점진적 마이그레이션
    모듈 단위로 자바 → 코틀린 전환이 가능하므로, 대규모 레거시 코드베이스에도 부담이 적습니다.

6. 멀티플랫폼 지원(Kotlin Multiplatform)

  • iOS·Android·백엔드·웹
    Kotlin/Native, Kotlin/JS를 이용해 한 코드베이스로 여러 플랫폼에 대응할 수 있습니다.
  • 공유 로직
    데이터 모델, 비즈니스 로직, 네트워킹 코드를 공통 모듈로 관리해 개발 생산성과 일관성을 높여 줍니다.

7. 현대적 언어 기능과 강력한 표준 라이브러리

  • DSL(Domain-Specific Language)
    빌더 스타일의 직관적인 DSL 작성으로, Gradle 스크립트나 HTML 생성도 깔끔하게 표현할 수 있습니다.
  • 표준 라이브러리 확장
    표준 라이브러리가 풍부한 유틸리티 함수를 제공해, 자주 쓰는 작업을 짧은 코드로 처리할 수 있습니다.

이처럼 코틀린은 안정성과 생산성, 가독성을 두루 갖춘 현대적 언어로, 안드로이드 앱은 물론 서버·웹·멀티플랫폼 개발에도 매우 매력적입니다. 프로젝트 규모나 요구사항에 맞춰 도입을 검토해 보시면 좋겠습니다!

[linux] 쉘스크립트 내에서 nohup 실행하기

#!/bin/bash
#
# ┌──────────────────────────────────────────────────────────────┐
# │   [Linux] nohup 기반 자바 애플리케이션 실행 및 프로세스 관리    │
# │   - PID 파일로 기존 프로세스 종료 후 재실행                        │
# └──────────────────────────────────────────────────────────────┘
#
# 사용 방법:
#   1. 이 스크립트를 서버에 복사합니다. (예: /usr/local/bin/run_app.sh)
#   2. 실행 권한을 부여합니다: chmod +x /usr/local/bin/run_app.sh
#   3. 애플리케이션을 실행/재실행할 때마다: ./run_app.sh
#
# 스크립트 동작 요약:
#   - program.pid 파일이 있으면, 해당 PID를 읽어와 프로세스 존재 여부를 확인하고 종료(SIGTERM → SIGKILL).
#   - nohup java -jar로 자바 애플리케이션을 백그라운드 실행.
#   - 표준 출력 및 표준 에러를 program.log로 모두 기록(Append).
#   - 새로 생성된 프로세스의 PID를 program.pid 파일에 기록.
#

# ───────────────────────────────────────────────────────────────────
# 1) 변수 설정: PID 파일, 로그 파일, JAR 파일 경로 (절대 경로 권장)
# ───────────────────────────────────────────────────────────────────
PID_FILE="/home/ubuntu/app/program.pid"
LOG_FILE="/home/ubuntu/app/program.log"
JAR_FILE="/home/ubuntu/app/program.jar"

# ───────────────────────────────────────────────────────────────────
# 2) 기존 프로세스 확인 및 종료
# ───────────────────────────────────────────────────────────────────
if [ -f "$PID_FILE" ]; then
    OLD_PID=$(cat "$PID_FILE" 2>/dev/null)
    if [ -n "$OLD_PID" ]; then
        # 2-1) PID가 실제로 실행 중인지 확인
        if ps -p "$OLD_PID" > /dev/null 2>&1; then
            echo "[INFO] 기존 프로세스(PID: $OLD_PID)를 종료합니다..."
            # 2-2) 우선 SIGTERM(SIG15)으로 정상 종료 시도
            kill -15 "$OLD_PID"
            # 2-3) 종료 대기 시간(예: 5초)
            sleep 5
            # 2-4) 여전히 프로세스가 살아 있으면 SIGKILL(SIG9)으로 강제 종료
            if ps -p "$OLD_PID" > /dev/null 2>&1; then
                echo "[WARN] SIGTERM으로 종료되지 않아 SIGKILL로 강제 종료합니다."
                kill -9 "$OLD_PID"
            fi
            echo "[INFO] 프로세스 $OLD_PID 종료 완료."
        else
            echo "[WARN] PID 파일은 존재하나, 해당 PID($OLD_PID) 프로세스가 이미 종료되어 있습니다."
        fi
    fi
    # 2-5) 이전 PID 파일 삭제
    rm -f "$PID_FILE"
    echo "[INFO] 이전 PID 파일을 삭제했습니다."
fi

# ───────────────────────────────────────────────────────────────────
# 3) 새로운 애플리케이션 백그라운드 실행 및 로그·PID 기록
# ───────────────────────────────────────────────────────────────────
echo "[INFO] 애플리케이션을 백그라운드에서 실행합니다..."
nohup java -jar "$JAR_FILE" >> "$LOG_FILE" 2>&1 &
NEW_PID=$!
echo "$NEW_PID" > "$PID_FILE"
echo "[INFO] 새 프로세스(PID: $NEW_PID)가 실행되었습니다."
echo "[INFO] 로그 파일: $LOG_FILE"
echo "[INFO] PID 파일: $PID_FILE"