글 작성하기 테스크_이미지 포함 파일 복붙

ch#01_강의자료 및 교안 공유

1-1. 바탕화면에 보관 폴더 생성. 

– 공유된 자료를 보관하는 전용 폴더 생성후

  배포되는 강의자료 또는 교안자료를 저장.

– 탐색기에서 바탕화면에 새폴더 생성.

  (단축키 ctrl + shift + n) 으로 

  폴더 생성. (폴더명 : AWS_강의자료)

1-2. 강의자료 다운로드 방법

* 접속 세션 만들기

– 사이트관리자에서 강사서버 session 생성. 

– 호스트이름 : n3tw0rk.kr

– 포트 : 2121

– 사용자 : aws2510

– 비밀번호 : aws12345

세션 정보를 입력후 연결.

1-3. 교안 공유 방법

* 단톡방에 공유된 링크를 통하여 Google Docs로 공유.

* 과목별로 웹브라우저에 북마크 등록하여 활용.

* 강의별 교안 링크 (임시)

– 오리엔테이션 :

https://docs.google.com/document/d/1KVG9iZd_iTq886s157JKraSYp_ZFzXjn1a8yrflE5Jc/edit?tab=t.0

– Linux 교안 : https://docs.google.com/document/d/1XeJBnbeyRDkS2cBxVlelRe-DuM1KVWHn3SJSxfj_Zsc/edit?pli=1&tab=t.0#heading=h.e4i8ix1rml2p

– 클라우드 교안 : https://docs.google.com/document/d/1DGaLIulEr6JnNjQuc7HvMb4YqqmVBMNVAVbcPXFwmyE/edit?tab=t.0#heading=h.85zlct9oldp6

– DBMS 교안 : https://docs.google.com/document/d/1lZiSKT8RSuTNqLDV4RfSXes-3yUPy_UEvOBI0jWP65w/edit?pli=1&tab=t.0#heading=h.sblvfdiuyj26

ch#02_실습프로그램

2-1. Filezilla(파일질라) : 파일 업/다운로드 프로그램

* 파일질라 공식 사이트(https://filezilla-project.org/)에서 프로그램 다운로드.

  • 클라이언트용 다운로드.
  • 윈도우 64bit용 선택.
  • 기본버전 선택.

* 다운로드 폴더에서 “FileZilla_3.69.3_win64_sponsored2-setup.exe” 

  설치파일 실행.

2-2. Moba X-TERM(모바엑스텀) : 원격접속 프로그램

* 공식사이트 https://mobaxterm.mobatek.net/download.html 에서 설치

  프로그램 다운로드. 

* 다운로드 받은 파일을 마우스 우클릭하여 압축풀기 한 다음에 설치파일을 실행. 

* 설치절차

2-3. HeidiSQL(하이디SQL) : MariaDB 접속 프로그램

* 공식사이트 http://www/heidisql.com 에서 설치프로그램 다운로드.

* 다운로드 폴더에서 “HeidiSQL_12.12.0.7122_Setup.exe” 설치파일 실행.

2-4. 가상화 시스템 : VMware 

1. Vmware 설치

* 공유자료의 “03.프로그램 폴더\01.01.VMware-Workstation-Pro 17.0.0”에 있는

  설치파일을 실행.

* 크랙설치

  “03.프로그램 폴더\01.01.VMware-Workstation-Pro 17.0.0”에 있는 

  “INSTALL ENG.cmd” 파일을 실행.

2. 가상시스템에 서버 만들기

  • VMware 실행-Create New Virtual Machine 클릭
  • Custom 선택-다음

* 실습용 서버 Specification

  – 서버name : webserver

  – OS : Centos 9 stream

  – CPU : 듀얼코어 2개

  – RAM : 2Gb

  – Sto : 30Gb

* 가상상네트워크 IP대역 변경 : 192.168.200.0 /24

  – 작업폴더 생성 : 바탕화면에 ServerRoom 폴더 생성. 

3. 서버에 운영체제(CentOS 9) 설치하기

ch#03_수업 Tip

3-1. 멀티 데스크탑

* 데스크탑 추가

 – Win + Ctrl + D 단축키를 활용하여 필요한 만큼 추가.

 – 작업표시줄에서 데스크탑 아이콘을 클릭해서 추가. 

* 화면분할 및 창크기 조절

– 프로그램을 화면비율에 맞게 분할하여 정렬기능.

– 프로그램을 선택하고 Win + 방향키로 위치 지정. 

– Win + ← : 화면 좌측에 위치(½ 비율)

– Win + → : 화면 우측에 위치(½ 비율)

– Win + ↓ 또는 ↑ : ¼ 비율

3-2. 유용한 윈도우 단축키

필수 단축키창 관리 및 탐색 단축키
단축키작업단축키작업
Win + E탐색기Win + Tab작업 보기
Alt + F4프로그램 종료Win + 방향키창크기 조절 및 이동
Ctrl + C복사하기Win + M창 최소화
Ctrl + V붙여넣기Alt + Tab창 전환
Win + R명령 실행창Win + L컴퓨터 잠금
Alt + 방향키작업 이전/이후Win + Ctrl + D데스크탑 화면 추가
Win + .(마침표)이모지 및 특수기호
Win + A알림센터

글작성하기 테스크_구글docs에서 복붙

1. 배경 (Background)

당신은 GPU 서버 관리팀의 일원입니다. 최근 교내 정전 사태로 인해 서버 전체가 재부팅되는 사고가 있었습니다. 이 과정에서 Docker 컨테이너들이 재시작 되었으나, DB에 저장된 설정 정보와 실제 구동 중인 컨테이너 상태 간에 데이터 불일치(Port, UID/GID 등)가 발생했습니다.

우선 수동으로 복구를 완료했으나, 향후 동일한 사태를 대비해 동료 A와 함께 자동화 스크립트(sync_containers.sh)를 작성하는 업무를 맡았습니다. 동료 A는 빠르게 스크립트를 작성하고, 당신에게 전달해주었습니다. 당신의 임무는 이 스크립트를 다른 동료도 쉽게 사용할 수 있도록 기술 문서를 작성하여 배포하는 것입니다.

2. 목표 (Objectives)

동료 A가 작성한 쉘 스크립트 코드를 분석하고, 다른 팀원들도 이 도구를 이해하고 사용할 수 있도록 하기 위한 기술 문서를 노션으로 작성하십시오.

3. 필수 포함 항목

제출하는 PDF 문서에는 다음의 내용이 반드시 포함되어야 합니다. (목차 구성은 자유입니다.)

  1. 스크립트 개요: 이 스크립트가 해결하고자 하는 문제와 핵심 동작 로직(Flow) 설명
  2. 사용 가이드:
    • 사용법 및 옵션 설명 (-dry-run 등)
  3. 코드 분석:
    • 주요 함수 또는 로직 블록별 기능 설명

4. 첨부 자료 (Source Code)

  • 파일명: sync_containers.sh
  • 작성자: 동료 A

#!/bin/bash

# ==========================================================

# sync_containers.sh

# DB 기준으로 컨테이너 상태 동기화

# 이미지/버전/UID/GID/포트 불일치 시 자동 recreate / 정지된 컨테이너 재시작

#   – –dry-run: 실제 실행하지 않고 시뮬레이션만

#   – –auto-delete: DB에 없는 컨테이너 자동 삭제

# ==========================================================

DB_ADDRESS=192.168.2.11

DB_PORT=3307

DB_NAME=”nfs_db”

DB_USER=”nfs_user”

DB_PASSWORD=”nfs_password”

DRY_RUN=false

AUTO_DELETE=false

# 옵션 파싱

for arg in “$@”; do

  case “$arg” in

    –dry-run) DRY_RUN=true ;;

    –auto-delete) AUTO_DELETE=true ;;

  esac

done

echo “[INFO] Using DB: $DB_NAME at $DB_ADDRESS:$DB_PORT”

echo “[INFO] Options: dry-run=$DRY_RUN, auto-delete=$AUTO_DELETE”

# MySQL 접속 설정 파일 생성

cat <<EOF > ~/.my.cnf

[client]

user=$DB_USER

password=$DB_PASSWORD

host=$DB_ADDRESS

port=$DB_PORT

EOF

chmod 600 ~/.my.cnf

# DB에서 컨테이너 목록 불러오기

containers=$(mysql -N -D $DB_NAME -e “

SELECT dc.container_name, dc.image, dc.image_version,

       u.ubuntu_username, u.ubuntu_uid, u.ubuntu_gid,

       dc.server_id, dc.id

FROM docker_container dc

JOIN user u 

ON dc.user_id=u.id

WHERE dc.existing=1;

“)

echo “[INFO] Loaded $(echo “$containers” | wc -l) containers from DB.”

# 서버 컨테이너 상태 확인

docker ps -a –format “{{.Names}} {{.Status}}” > /tmp/docker_status.txt

while read -r cname image version uname uid gid sid dbid; do

    server_status=$(grep -w “$cname” /tmp/docker_status.txt | awk ‘{print $2}’)

    # (1) DB에 있고 서버에는 없는 경우

    if [ -z “$server_status” ]; then

        echo “[CREATE] $cname (image=$image:$version, user=$uname)”

        ports=$(mysql -N -D $DB_NAME -e “

            SELECT port_number, purpose_of_use FROM used_ports

            WHERE docker_container_record_id=$dbid;

        “)

        port_args=””

        while read -r port purpose; do

            [ -z “$port” ] && continue

            if ss -tulpn | grep -q “:$port “; then

                echo “[SKIP] Port $port ($purpose) already in use”

                continue

            fi

            case “$purpose” in

                ssh) port_args=”$port_args -p ${port}:22″ ;;

                “jupyter notebook”) port_args=”$port_args -p ${port}:8888″ ;;

                *) port_args=”$port_args -p ${port}:${port}” ;;

            esac

        done <<< “$ports”

        if $DRY_RUN; then

            echo “[DRY-RUN] docker run -dit $port_args –name $cname …”

        else

            docker run -dit \\

                –name “$cname” \\

                $port_args \\

                -e USER_ID=$uname -e UID=$uid -e GID=$gid \\

                dguailab/$image:$version

        fi

        continue

    fi

    # (2) 서버에는 있는데 정지된 경우

    if [ “$server_status” == “Exited” ]; then

        if $DRY_RUN; then

            echo “[DRY-RUN] restart $cname”

        else

            echo “[RESTART] $cname”

            docker start “$cname”

        fi

        continue

    fi

    # (3) 서버/DB 세부정보 비교 (이미지/UID/GID/포트)

    mismatch=false

    actual_image=$(docker inspect –format ‘{{.Config.Image}}’ “$cname” 2>/dev/null)

    if [ “$actual_image” != “dguailab/$image:$version” ]; then

        echo “[MISMATCH] Image differs: DB=$image:$version, Actual=$actual_image”

        mismatch=true

    fi

    actual_uid=$(docker inspect –format ‘{{range .Config.Env}}{{println .}}{{end}}’ “$cname” | grep ‘^UID=’ | cut -d= -f2)

    actual_gid=$(docker inspect –format ‘{{range .Config.Env}}{{println .}}{{end}}’ “$cname” | grep ‘^GID=’ | cut -d= -f2)

    if [ “$actual_uid” != “$uid” ] || [ “$actual_gid” != “$gid” ]; then

        echo “[MISMATCH] UID/GID differs: DB=$uid/$gid, Actual=$actual_uid/$actual_gid”

        mismatch=true

    fi

    db_ports=$(mysql -N -D $DB_NAME -e “

        SELECT port_number FROM used_ports

        WHERE docker_container_record_id=$dbid;

    ” | sort)

    actual_ports_sorted=$(docker inspect “$cname” \\

  | jq -r ‘[.[] | .NetworkSettings.Ports | to_entries[] | .value[]?.HostPort] | unique | .[]’ \\

  | sort -n | tr ‘\\n’ ‘ ‘ | sed ‘s/ *$//’)

    if [ “$db_ports” != “$actual_ports” ]; then

        echo “[MISMATCH] Ports differ”

        echo ”  DB: $db_ports”

        echo ”  Actual: $actual_ports”

        mismatch=true

    fi

    # 불일치 시 재생성

    if $mismatch; then

        if $DRY_RUN; then

            echo “[DRY-RUN] Would recreate $cname”

        else

            echo “[RECREATE] $cname”

            docker rm -f “$cname”

            ports=$(mysql -N -D $DB_NAME -e “

                SELECT port_number, purpose_of_use FROM used_ports

                WHERE docker_container_record_id=$dbid;

            “)

            port_args=””

            while read -r port purpose; do

                [ -z “$port” ] && continue

                case “$purpose” in

                    ssh) port_args=”$port_args -p ${port}:22″ ;;

                    “jupyter notebook”) port_args=”$port_args -p ${port}:8888″ ;;

                    *) port_args=”$port_args -p ${port}:${port}” ;;

                esac

            done <<< “$ports”

            docker run -dit \\

                –name “$cname” \\

                $port_args \\

                -e USER_ID=$uname -e UID=$uid -e GID=$gid \\

                dguailab/$image:$version

        fi

    else

        echo “[OK] $cname is running and matches DB”

    fi

done <<<“$containers”

# (4) 서버에 있고 DB에는 없는 경우

server_only=$(comm -23 <(awk ‘{print $1}’ /tmp/docker_status.txt | sort) \\

                      <(echo “$containers” | awk ‘{print $1}’ | sort))

if [ -n “$server_only” ]; then

    if $AUTO_DELETE; then

        for cname in $server_only; do

            if $DRY_RUN; then

                echo “[DRY-RUN] Would delete $cname (not in DB)”

            else

                echo “[DELETE] $cname (not in DB)”

                docker rm -f “$cname”

            fi

        done

    else

        echo “[WARN] Containers on server but not in DB:”

        echo “$server_only”

    fi

fi

echo “[DONE] Sync completed.”

Cf. 위 source 코드를 이해하기 위한 추가자료

  • MySQL 테이블 및 뷰 정의 sql

— Create the database with explicit character set

CREATE DATABASE IF NOT EXISTS nfs_db CHARACTER

SET

    = utf8mb4 COLLATE = utf8mb4_unicode_ci;

USE nfs_db;

— Create used_ids table for ID management

CREATE TABLE

    used_ids (id INT PRIMARY KEY AUTO_INCREMENT) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;

— Create group table

CREATE TABLE

    `group` (

        id INT PRIMARY KEY AUTO_INCREMENT,

        ubuntu_groupname VARCHAR(255) NOT NULL,

        ubuntu_gid INT NOT NULL,

        UNIQUE KEY unique_gid (ubuntu_gid),

        FOREIGN KEY (ubuntu_gid) REFERENCES used_ids (id)

    ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;

— Create user table without circular references

CREATE TABLE

    user (

        id INT PRIMARY KEY AUTO_INCREMENT,

        name VARCHAR(255) NOT NULL,

        ubuntu_username VARCHAR(255) NOT NULL,

        ubuntu_uid INT NOT NULL,

        ubuntu_gid INT,

        note TEXT,

        UNIQUE KEY unique_uid (ubuntu_uid),

        FOREIGN KEY (ubuntu_uid) REFERENCES used_ids (id),

        FOREIGN KEY (ubuntu_gid) REFERENCES `group` (ubuntu_gid)

    ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;

— Create docker_container table

CREATE TABLE

    docker_container (

        id INT PRIMARY KEY AUTO_INCREMENT,

        image VARCHAR(255) NOT NULL,

        image_version VARCHAR(50) NOT NULL,

        container_id VARCHAR(64) NOT NULL,

        container_name VARCHAR(255) NOT NULL,

        server_id VARCHAR(255) NOT NULL,

        expiring_at DATETIME NOT NULL,

        deleted_at DATETIME,

        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,

        existing BOOLEAN DEFAULT TRUE,

        created_by VARCHAR(255),

        user_id INT,

        UNIQUE KEY unique_container (container_id),

        FOREIGN KEY (user_id) REFERENCES user (id)

    ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;

— Create used_ports table after docker_container exists

CREATE TABLE

    used_ports (

        port_number INT PRIMARY KEY,

        docker_container_record_id INT,

        purpose_of_use VARCHAR(255),

        FOREIGN KEY (docker_container_record_id) REFERENCES docker_container (id)

    ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;

— Add indexes

CREATE INDEX idx_container_existing ON docker_container (existing);

CREATE INDEX idx_container_expiring ON docker_container (expiring_at);

CREATE INDEX idx_user_username ON user (ubuntu_username);

— Verify character set settings

SET

    NAMES utf8mb4;

CREATE VIEW

    user_container_info AS

SELECT

    u.name AS ‘사용자 이름’,

    u.ubuntu_username AS ‘우분투 아이디’,

    g.ubuntu_groupname AS ‘우분투 그룹 이름’,

    dc.server_id AS ‘배정된 서버’,

    (

        SELECT

            up.port_number

        FROM

            used_ports up

        WHERE

            up.docker_container_record_id = dc.id

            AND up.purpose_of_use = ‘ssh’

    ) AS ‘ssh 포트’,

    (

        SELECT

            up.port_number

        FROM

            used_ports up

        WHERE

            up.docker_container_record_id = dc.id

            AND up.purpose_of_use = ‘jupyter notebook’

    ) AS ‘jupyter 포트’,

    (

        SELECT

            GROUP_CONCAT (up.port_number) # 오류 : 빨간색 삭제

        FROM

            used_ports up

        WHERE

            up.docker_container_record_id = dc.id

            AND up.purpose_of_use != ‘ssh’

            AND up.purpose_of_use != ‘jupyter notebook’

    ) AS ‘할당된 다른 포트’,

    dc.expiring_at AS ‘사용 만료일’,

    dc.created_by AS ‘컨테이너 생성한 관리자’,

    dc.created_at AS ‘컨테이너 생성 일자’,

    dc.image AS ‘컨테이너 이미지’,

    dc.image_version AS ‘컨테이너 버전’,

    dc.container_name AS ‘컨테이너 이름’,

    u.note AS ‘노트’

FROM

    user u

    LEFT JOIN `group` g ON u.ubuntu_gid = g.ubuntu_gid

    JOIN docker_container dc ON u.id = dc.user_id

WHERE

    dc.existing = TRUE

ORDER BY

    dc.server_id ASC,

    u.name ASC;