Linux에서는 Parent Process가 fork()를 통해 Child Process를 만들고, Child Process에서 execve()를 통해 새로운 Program을 실행할 수 있다.
Parent Process
│
│
fork()
/ \
/ \
/ \
Parent Process Child Process
│ │
│ execve()
│ │
│ 새로운 프로그램 실행
│ │
wait() │
│ exit(status)
│ │
│◀──── 종료 상태 전달
│
wait() 반환
│
부모 실행 계속
Process 확인과 제어에 사용한 명령어는 다음과 같다.
ps
ps -ef
pstree
pgrep
kill
jobs
fg %1
bg %1
ps -e : System의 모든 Process 출력ps -f : 상세 정보 출력pstree : Parent-Child 관계 확인jobs : Background 작업 확인fg / bg : Foreground와 Background 전환여러 File을 하나로 묶을 때 tar를 사용한다.
-c : 새로운 tar 파일 생성
-t : tar 파일의 내부 내용들의 리스트 확인
-x : tar 파일 해제
-k : 덮어씌움 방지
-f : 아카이브 파일이나 테이프 장치를 지정
-v : tar 명령어 수행과정 자세히 출력
-h : 아카이브하려는 파일이 심볼릭 링크인 경우 원본을 아카이브
-z : gz로 압축 진행
Compression에는 gzip, bzip2, zip 등을 사용할 수 있다.
gzip
gunzip
bzip2
bzcat
zip
unzip
Archive는 여러 File을 하나로 묶는 것이고 Compression은 Data Size를 줄이는 과정이다.
사용자와 Group 관련 주요 File은 다음과 같다.
/etc/passwd
/etc/shadow
/etc/group
/etc/gshadow
/etc/passwd : 사용자 정보/etc/shadow : Password 정보/etc/group : Group 정보/etc/gshadow : Group Password 정보Linux에서는 사용자 이름보다 UID를 기준으로 Permission을 판단한다.
실습에서는 두 사용자에게 같은 UID를 설정했을 때 Linux가 동일한 사용자처럼 판단하는 것을 확인했다.
nobreak@rocky-node1:~$ sudo useradd test11
nobreak@rocky-node1:~$ sudo usermod -u 1000 -o test11
nobreak@rocky-node1:~$ id test11
uid=1000(nobreak) gid=1002(test11) groups=1000(nobreak)
사용자 설정 변경:
-a : 기존 보조 그룹 유지하면서 추가
-L : 계정 잠금
-U : 계정 잠금 해제
Group을 추가할 때는 기존 보조 Group을 유지하도록 -aG를 함께 사용하는 것이 중요하다.
sudo usermod -aG admins student6
사용자 삭제:
sudo userdel testuser
Home Directory까지 함께 삭제:
sudo userdel -r testuser
-r 없이 삭제하면 사용자 계정은 사라져도 Home Directory는 남을 수 있다.
Group 생성:
nobreak@rocky-node1:~$ sudo groupadd -g 989 apache
Group 이름과 GID 변경:
nobreak@rocky-node1:~$ sudo groupmod -n apache2 apache
nobreak@rocky-node1:~$ sudo groupmod -g 3000 apache2
nobreak@rocky-node1:~$ grep apache2 /etc/group
apache2:x:3000:
Group 삭제:
nobreak@rocky-node1:~$ sudo groupdel apache2
기본 Group으로 사용되고 있다면 바로 삭제할 수 없다.
/etc/skel은 새로운 사용자의 Home Directory에 기본적으로 들어갈 File을 관리한다.
실습에서는 welcome.txt와 .bashrc 설정을 추가했다.
nobreak@rocky-node1:~$ sudo touch /etc/skel/welcome.txt
nobreak@rocky-node1:~$ echo 'echo "Welcome $USER"' | sudo tee -a /etc/skel/.bashrc
echo "Welcome $USER"
이후 새로운 사용자를 생성하였다.
nobreak@rocky-node1:~$ sudo useradd student11
nobreak@rocky-node1:~$ sudo su - student11
Welcome student11
새 사용자에게만 /etc/skel의 내용이 복사되며 기존 사용자에게는 자동 적용되지 않는다.
su는 현재 Session에서 다른 사용자로 전환한다.
su
su -
su -는 Login Shell 형태로 전환하여 해당 사용자의 환경까지 새로 적용한다.
sudo는 허가된 사용자가 root 등의 권한으로 Command를 실행한다.
대표적인 sudo 설정은 /etc/sudoers에서 확인할 수 있다.
root ALL=(ALL) ALL
%wheel ALL=(ALL) ALL
# %wheel ALL=(ALL) NOPASSWD: ALL
%는 Group을 의미한다.
Root Permission이 필요한 File에 Redirection할 때 tee를 활용할 수 있다.
nobreak@rocky-node1:~$ echo "hello" | tee hello.txt
hello
nobreak@rocky-node1:~$ cat hello.txt
hello
sudo와 함께 사용할 수도 있다.
echo "내용" | sudo tee /root/file
Linux에서는 Process를 생성·제어하고, UID·GID를 기반으로 사용자와 Group을 관리하며
sudo를 통해 높은 권한의 Command 실행을 통제한다.
새로운 사용자에게 공통 File을 제공하도록 /etc/skel을 설정하였다.
nobreak@rocky-node2:~$ echo "welcome" | sudo tee /etc/skel/welcome.txt
welcome
nobreak@rocky-node2:~$ sudo useradd student4
nobreak@rocky-node2:~$ sudo ls -l /home/student4/
total 4
-rw-r--r--. 1 student4 student4 8 Sep 29 00:35 welcome.txt
.bashrc에도 Login Message를 추가했다.
nobreak@rocky-node2:~$ echo "echo 'hello'" | sudo tee -a /etc/skel/.bashrc
echo 'hello'
nobreak@rocky-node2:~$ sudo useradd -m student5
nobreak@rocky-node2:~$ sudo su - student5
hello
student5@rocky-node2:~$ exit
logout
sudo를 사용할 admins Group도 구성하였다.
nobreak@rocky-node2:~$ sudo groupadd admins
nobreak@rocky-node2:~$ sudo visudo -f /etc/sudoers.d/admins
nobreak@rocky-node2:~$ sudo cat /etc/sudoers.d/admins
%admins ALL=(ALL) ALL
nobreak@rocky-node2:~$ sudo useradd student6
nobreak@rocky-node2:~$ sudo usermod -aG admins student6
sudo 사용 기록은 다음 Log에서 확인했다.
nobreak@rocky-node2:~$ sudo cat /var/log/secure
일반 사용자는 /etc/shadow를 읽을 수 없다.
nobreak@rocky-node2:~$ mkdir perm_prac
nobreak@rocky-node2:~$ cp /bin/cat ~/perm_prac/secret_cat
nobreak@rocky-node2:~$ perm_prac/secret_cat /etc/shadow
perm_prac/secret_cat: /etc/shadow: Permission denied
File Owner를 root로 변경하였다.
nobreak@rocky-node2:~$ sudo chown root perm_prac/secret_cat
setuid를 설정하였다.
nobreak@rocky-node2:~$ sudo chmod u+s perm_prac/secret_cat
Permission은 다음과 같이 변경된다.
-rwsr-xr-x. 1 root nobreak 69456 Sep 30 00:06 perm_prac/secret_cat
이후 일반 사용자로 실행해도 File Owner인 root의 Effective Permission으로 Program이 실행되어 /etc/shadow에 접근할 수 있었다.
| Permission | 기호 | 역할 |
|---|---|---|
| setuid | s | 실행 시 File Owner 권한 사용 |
| setgid | s | File에서는 Group 권한 사용, Directory에서는 Group 상속 |
| Sticky Bit | t | 공유 Directory에서 다른 사용자의 File 삭제 제한 |
Sticky Bit 실습에서는 먼저 모든 사용자가 Write 가능한 Directory를 만들었다.
nobreak@rocky-node2:~$ mkdir /tmp/testdir
nobreak@rocky-node2:~$ chmod 777 /tmp/testdir/
user01이 만든 File을 user02가 삭제할 수 있었다.
Sticky Bit 설정:
nobreak@rocky-node2:~$ chmod +t /tmp/testdir/
nobreak@rocky-node2:~$ ls -ld /tmp/testdir/
drwxrwxrwt. 2 nobreak nobreak 6 Sep 29 01:26 /tmp/testdir/
이후 다른 사용자의 File 삭제가 차단되었다.
rm: cannot remove '/tmp/testdir/fileA': Operation not permitted
기본 Owner / Group / Others 구조에 포함되지 않는 특정 사용자에게 Permission을 줄 때 ACL을 사용할 수 있다.
root@rocky-node2:~# setfacl -m u:user01:rw acl/files/file1.txt
root@rocky-node2:~# ls -l acl/files/file1.txt
-rw-rw-r--+ 1 root root 10 Sep 29 02:08 acl/files/file1.txt
root@rocky-node2:~# getfacl acl/files/file1.txt
# file: acl/files/file1.txt
# owner: root
# group: root
user::rw-
user:user01:rw-
group::r--
mask::rw-
other::r--
ACL의 mask는 실제 적용할 수 있는 최대 Permission을 제한한다.
user:user1:rw- #effective:r-
group::r--
mask::r--
반복 작업 Scheduling에는 crontab을 사용한다.
-e : crontab 파일 편집
-l : crontab 파일 내용 출력
-r : crontab 파일 삭제
Cron 구조:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12)
# | | | | .---- day of week (0 - 6)
# | | | | |
# * * * * * command
수업에서 사용한 예시는 다음과 같다.
# 매일 02:00에 실행
0 2 * * *
# 평일 09:00에 실행
0 9 * * 1-5
# 10분마다 실행
*/10 * * * *
# 2시간마다 실행
0 */2 * * *
# 분기별 첫날에 실행
0 0 1 1,4,7,10 *
# 5분 마다 현재 시스템의 메모리 사용량 확인 및 결과를 ~/memory_log.txt 파일에 추가
*/5 * * * * free -h >> ~/memory_log.txt
# 매일 오후 2시 30분에 홈 디렉토리의 .tmp 파일을 모두 삭제하는 작업
30 14 * * * find ~ -name "*.tmp" -type -f -delete
Cron 실행 시점에 System이 꺼져 있으면 작업이 누락될 수 있다.
Anacron은 System이 다시 실행되었을 때 작업 주기를 확인해 누락된 작업을 실행할 수 있다.
1 5 cron.daily
7 25 cron.weekly
@monthly 45 cron.monthly
setuid·setgid·Sticky Bit와 ACL을 이용해 기본 Permission보다 세밀한 권한을 설정하고, Cron과 Anacron을 이용해 반복 작업을 자동 실행할 수 있다.
Disk의 Partition Table은 대표적으로 MBR과 GPT 방식으로 나뉜다.
| 구분 | MBR | GPT |
|---|---|---|
| Firmware | BIOS | UEFI |
| 특징 | 기존 Partition 방식 | GUID 기반 Partition 방식 |
| 대용량 Disk | 약 2TB 제한 | 매우 큰 Disk 지원 |
Partition은 fdisk를 이용해 관리했다.
root@rocky-node2:~# fdisk /dev/sdb
주요 Command는 다음과 같다.
d delete a partition
l list known partition types
n add a new partition
p print the partition table
t change a partition type
w write table to disk and exit
q quit without saving changes
g create a new empty GPT partition table
o create a new empty MBR (DOS) partition table
Partition 생성 후 XFS 등의 File System을 만들고 Mount하여 사용한다.
Disk는 Partition Table → Partition → File System → Mount 과정을 거쳐 Linux의 Directory 구조에 연결된다.
LVM은 다음 구조로 Storage를 관리한다.
Partition
↓
PV
↓
VG
↓
LV
↓
File System
↓
Mount
Partition Type을 Linux LVM으로 변경하였다.
root@rocky-node2:~# fdisk /dev/sdb
Command (m for help): t
Selected partition 1
Hex code or alias (type L to list all): 8e
Changed type of partition 'Linux' to 'Linux LVM'.
PV 생성:
root@rocky-node2:~# pvcreate /dev/sdb1
Physical volume "/dev/sdb1" successfully created.
VG 생성:
root@rocky-node2:~# vgcreate vg_test /dev/sdb1
Volume group "vg_test" successfully created
LV 생성:
root@rocky-node2:~# lvcreate -n lv_test -L 5G vg_test
Logical volume "lv_test" created.
XFS 생성:
root@rocky-node2:~# mkfs.xfs /dev/vg_test/lv_test
Mount:
root@rocky-node2:~# mkdir /lvmtest
root@rocky-node2:~# mount /dev/vg_test/lv_test /lvmtest
root@rocky-node2:~# df -h /lvmtest
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/vg_test-lv_test 5.0G 130M 4.9G 3% /lvmtest
1GB File 생성:
root@rocky-node2:~# sudo dd if=/dev/zero of=/lvmtest/testfile bs=1M count=1000
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 0.222304 s, 4.7 GB/s
Logical Volume을 5GB에서 8GB로 확장하였다.
root@rocky-node2:~# lvextend -L 8G /dev/vg_test/lv_test
Size of logical volume vg_test/lv_test changed from 5.00 GiB (1280 extents) to 8.00 GiB (2048 extents).
Logical volume vg_test/lv_test successfully resized.
하지만 File System은 아직 5GB로 인식하고 있었다.
/dev/mapper/vg_test-lv_test 5.0G 1.2G 3.9G 23% /lvmtest
XFS File System까지 확장하였다.
root@rocky-node2:~# xfs_growfs /lvmtest/
확인:
root@rocky-node2:~# df -h | grep vg
/dev/mapper/vg_test-lv_test 8.0G 1.2G 6.8G 15% /lvmtest
Snapshot 생성:
root@rocky-node2:~# lvcreate -L 1G --snapshot --name lv_test_snap /dev/vg_test/lv_test
Logical volume "lv_test_snap" created.
Snapshot 생성 후 원본에 File을 추가했다.
root@rocky-node2:~# touch /lvmtest/snapshot.txt
XFS Snapshot은 원본과 같은 UUID를 사용하므로 그대로 Mount했을 때 Error가 발생했다.
이를 무시하고 Mount:
root@rocky-node2:~# mount -o nouuid /dev/vg_test/lv_test_snap /snap
원본과 Snapshot을 비교하였다.
root@rocky-node2:~# ls -al /snap
total 1024000
drwxr-xr-x. 2 root root 22 Sep 30 08:29 .
dr-xr-xr-x. 20 root root 262 Sep 30 08:38 ..
-rw-r--r--. 1 root root 1048576000 Sep 30 08:29 testfile
root@rocky-node2:~# ls -al /lvmtest
total 1024000
drwxr-xr-x. 2 root root 42 Sep 30 08:37 .
dr-xr-xr-x. 20 root root 262 Sep 30 08:38 ..
-rw-r--r--. 1 root root 0 Sep 30 08:37 snapshot.txt
-rw-r--r--. 1 root root 1048576000 Sep 30 08:29 testfile
LVM은 PV → VG → LV 구조로 Disk를 논리적으로 관리하며, Logical Volume을 확장하거나 Snapshot을 생성하여 Storage를 유연하게 운영할 수 있다.
Disk
↓
Partition
↓
PV
↓
VG
↓
LV
↓
File System
↓
Mount Point
LVM에서는 단순 Partition과 달리 Logical Volume을 필요한 크기로 생성하고 이후에도 확장할 수 있다는 점이 핵심이다.
Service 상태 확인:
nobreak@rocky-node2:~$ systemctl status sshd.service
주요 Command:
start
stop
status
enable
disable
restart
reload
restart와 reload는 차이가 있다.
restart : Service를 종료 후 다시 실행reload : Service는 유지하고 설정 File만 다시 읽음Boot 자동 실행 여부 확인:
nobreak@rocky-node2:~$ systemctl is-enabled sshd.service
enabled
Unit File 수정 후:
sudo systemctl daemon-reload
를 사용한다.
Script 생성:
root@rocky-node2:~# mkdir /opt/scripts
root@rocky-node2:~# vi /opt/scripts/hello.sh
#!/bin/bash
while true; do
echo "Hello, systemd!!" >> /var/log/hello.log
sleep 10
done
root@rocky-node2:~# chmod +x /opt/scripts/hello.sh
Unit 생성:
[Unit]
Description=Hello service
After=network.target
[Service]
Type=simple
ExecStart=/opt/scripts/hello.sh
Restart=always
[Install]
WantedBy=multi-user.target
적용:
root@rocky-node2:~# systemctl daemon-reload
root@rocky-node2:~# systemctl start hello.service
root@rocky-node2:~# systemctl status hello.service
Log 확인:
root@rocky-node2:~# tail -f /var/log/hello.log
Hello, systemd!!
Hello, systemd!!
Hello, systemd!!
Custom Log File을 생성하였다.
nobreak@rocky-node2:~$ sudo mkdir -p /var/log/testlog
nobreak@rocky-node2:~$ sudo touch /var/log/testlog/testlog.log
nobreak@rocky-node2:~$ sudo dd if=/dev/zero of=/var/log/testlog/testlog.log bs=512 count=10
Custom logrotate 설정:
/var/log/testlog/testlog.log {
size=3k
create 600 root root
rotate 3
nodateext
}
Log Rotation 실행:
nobreak@rocky-node2:~$ sudo logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf
rotate 3이므로 오래된 Log는 최대 3개까지 유지된다.
systemd를 이용해 Service Lifecycle을 관리하고, journald와 logrotate를 통해 지속적으로 생성되는 System Log를 관리할 수 있다.
systemd-journald가 수집한 Journal은 journalctl로 조회한다.
-p : 우선순위 지정하여 출력
-n : 최근 저장된 저널부터 일정 개수의 저널 조회 가능
-f : 실시간 저널 모니터링
-u : 특정 systemd 유닛/서비스의 로그만 필터링
Persistent Journal Directory 생성:
root@rocky-node2:~# mkdir -p /var/log/journal
root@rocky-node2:~# systemd-tmpfiles --create --prefix /var/log/journal
root@rocky-node2:~# journalctl --flush
Boot 흐름은 다음과 같이 정리할 수 있다.
Power On
↓
BIOS / UEFI
↓
POST
↓
GRUB2
↓
Kernel + initramfs
↓
systemd (PID 1)
↓
Target
↓
Service
현재 Default Target 확인:
root@rocky-node2:~# systemctl get-default
multi-user.target
Default Target 변경:
root@rocky-node2:~# systemctl set-default graphical.target
Runtime Target 변경:
root@rocky-node2:~# systemctl isolate multi-user.target
RPM Package 확인:
nobreak@rocky-node2:~$ rpm -q rsyslog
rsyslog-8.2510.0-5.el10.aarch64
설치된 모든 RPM 확인:
rpm -qa
상세 정보:
rpm -qi rsyslog
Dependency 확인:
rpm -qR rsyslog
DNF에서는 Package 검색과 Repository 기반 설치가 가능하다.
dnf search apache
dnf info httpd
dnf list available
dnf list installed
dnf provides /etc/ssh/sshd_config
Repository Metadata 생성:
nobreak@rocky-node2:~$ sudo createrepo_c /localrepo/
Repository 설정:
[localrepo]
name=Local Repo
baseurl=file:///localrepo/
enabled=1
gpgcheck=0
Cache 갱신:
nobreak@rocky-node2:~$ sudo dnf clean all
nobreak@rocky-node2:~$ dnf makecache
Local Repository만 사용하여 설치:
nobreak@rocky-node2:~$ sudo dnf --disablerepo="*" --enablerepo="localrepo" install httpd -y
Linux는 GRUB2 → Kernel → systemd 순서로 Boot되고, Journal과 rsyslog로 Log를 관리하며 RPM·DNF Repository를 이용해 Software를 관리한다.
Interface 확인:
nobreak@rocky-node2:~$ ip a
IPv4만 확인:
nobreak@rocky-node2:~$ ip -4 a
Routing Table:
nobreak@rocky-node2:~$ ip route
default via 172.16.174.2 dev enp2s0 proto dhcp src 172.16.174.130 metric 101
172.16.174.0/24 dev enp2s0 proto kernel scope link src 172.16.174.130 metric 101
192.168.100.0/24 dev enp18s0 proto kernel scope link src 192.168.100.11 metric 100
NetworkManager 상태 확인:
nobreak@rocky-node2:~$ systemctl status NetworkManager
Connection 확인:
nobreak@rocky-node2:~$ nmcli connection show
동적 Connection 생성:
nobreak@rocky-node2:~$ sudo nmcli connection add type ethernet con-name "my-dynamic" ifname enp2s0 autoconnect yes
Static Connection 생성:
nobreak@rocky-node2:~$ sudo nmcli connection add type ethernet con-name "my-static" ifname enp2s0 ipv4.method manual ipv4.addresses 192.168.1.100/24 ipv4.gateway 192.168.1.1
DNS 설정:
nobreak@rocky-node2:~$ sudo nmcli connection modify my-static ipv4.dns "8.8.8.8 1.1.1.1"
Connection 활성화:
sudo nmcli connection up my-static
SSH로 접속 중인 Interface의 IP를 변경하면 현재 SSH Session이 끊길 수 있다는 것을 실습에서 확인했다.
현재 Hostname 확인:
nobreak@rocky-node2:~$ hostname
rocky-node2
변경:
nobreak@rocky-node2:~$ sudo hostnamectl hostname "rocky10"
nobreak@rocky-node2:~$ hostname
rocky10
또는:
nobreak@rocky-node2:~$ sudo hostnamectl set-hostname "rocky11"
nobreak@rocky-node2:~$ hostname
rocky11
변경 내용은 /etc/hostname에도 반영된다.
Client에서 Key Pair를 생성하였다.
nobreak@client:~$ ssh-keygen -t ed25519 -f ~/.ssh/client_key
Public Key를 Server에 등록하였다.
sudo ssh-copy-id -i ~/.ssh/client_key.pub testuser@192.168.58.88
구조는 다음과 같다.
Client
├── Private Key
└── Public Key
↓
Server
Server 정보를 기존에 저장한 known_hosts에서 제거하였다.
nobreak@client:~$ ssh-keygen -R 192.168.58.88
# Host 192.168.58.88 found: line 1
# Host 192.168.58.88 found: line 2
# Host 192.168.58.88 found: line 3
/home/nobreak/.ssh/known_hosts updated.
Original contents retained as /home/nobreak/.ssh/known_hosts.old
다시 접속하면 Server Fingerprint를 다시 확인한다.
The authenticity of host '192.168.58.88 (192.168.58.88)' can't be established.
ED25519 key fingerprint is SHA256:H0UKn76AgAiLlS4/mbcb7P3hdqxXTMnBC16zpxcbA/k.
Are you sure you want to continue connecting (yes/no/[fingerprint])?
Server의 Host Public Key는 다음과 같이 확인하였다.
testuser@server:~$ cat /etc/ssh/ssh_host_ed25519_key.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB8YF5GAWnLnZ8sMAGGwtHjvln9ShUpbCPFNGcpUnZvF root@server
Client에서 Server로 File 전송:
scp -i ~/.ssh/client_key testfile.txt 'testuser@192.168.58.88:~/'
Server에서 Client로 File 가져오기:
scp -i ~/.ssh/client_key 'testuser@192.168.58.88:~/testfile.txt' ./download_file
Directory 전체 전송:
nobreak@client:~$ scp -r test_dir/ testuser:~/
file2 100% 0 0.0KB/s 00:00
file3 100% 0 0.0KB/s 00:00
file1 100% 0 0.0KB/s 00:00
NetworkManager로 Linux Network 설정을 관리하고, SSH Key와 Server Fingerprint를 이용해 Remote Server를 확인하고 접속하며 SCP로 File을 전송할 수 있다.
Day 13~17의 Linux 수업은 앞으로 다음처럼 별도의 TIL 단위로 관리하는 편이 적합하다.
프로세스·사용자 관리
↓
고급 권한·Scheduling
↓
Disk·LVM
↓
Service·Log·Boot·Package
↓
Network·SSH
특히 실습 비중이 높은 Linux 수업에서는 개념을 길게 설명하기보다 실제로 실행한 명령어 → 결과 → 해당 실습에서 확인한 동작을 중심으로 정리한다.