◾️ 가상화 소프트웨어
- VMware Workstation Pro 17
- eve-ng
1. eve-ng VM 생성
2. eve-ng 접속
◾️ 네트워크 구축
- 세세한 설정 방법에 대해서는 다루지 않음.
- 설정 결과만 공유
1. VLAN 설정
1-1. Access Port
show vlan brief
1-2. Trunk Port
show interface trunk
2. Etherchannel
show etherchannel summary
스위치1, 스위치2에서 etherchannel 설정.
3. DHCP 설정 (Router 장비에서 진행)
show ip dhcp pool
3-1. DHCP Client(각 서버들)에서 IP 할당 받기
sudo dhclient -v
4. NAT 설정
4-1. 정방향 NAT 설정
show ip nat staticstics
4-2. 역방향 NAT 설정
show ip nat translations
◾️ 서버 상세 정보
시스템명 | 버전 |
---|---|
NGINX | Ubuntu 22.04.03 nginx: latest |
WEB | Ubuntu 22.04.03 FastAPI Github : [https://github.com/JaehyoJJAng/shortenURL |
](https://github.com/JaehyoJJAng/shortenURL) | |
DATABASE | Ubuntu 22.04.03 mysql:latest |
NFS | Ubuntu 22.04.03 nfs-common:latest |
SMB | Ubuntu 22.04.03 samba:latest |
Docker | V20.10.15 |
Docker Compose | V2.5.0 |
◾️ 서버 구축
내부망 서버의 접근 방식은 아래와 같다.
외부망 관리자 PC -> Bastion SSH 접속 -> 내부망 서버 SSH 접속
▪️ 사전 준비
- 본격적인 서버 구축 전에 해야 할 사전 작업 목록
1. 서버별 hostname 수정
# 모든 서버에서 진행
sudo hostnamectl set-hostname <서버이름>
sudo hostnamectl set-hostname nginx
2. 도커 설치
(도커가 필요한 서버(web,monitoring)에서만 진행합니다)
2-1. 도커 설치
[Docker] 도커 설치하기 - Install Docker [CentOS7] <- 해당 포스팅 참고하여 도커 설치
▪️ bastion
▪️ SSH 설정
외부망 대역(192.168.219.10)에 있는 관리자 PC에서 bastion으로 SSH 접속하여
내부망에 연결되어있는 서버들(nginx,web,db ..)을 관리해 줄 것이다.
먼저, bastion 서버의 /etc/hosts 파일에 각 내부 서버들의 hostname과 IP를 설정해주도록 하자.
Server | IP Address |
---|---|
nginx | 172.16.0.34 |
web | 172.16.0.37 |
db | 172.16.0.35 |
nfs | 172.16.0.66 |
samba | 172.16.0.67 |
monitoring | 172.16.0.70 |
sudo sh -c 'cat >> /etc/hosts << EOF
172.16.0.34 nginx
172.16.0.37 web
172.16.0.35 db
172.16.0.66 nfs
172.16.0.67 samba
172.16.0.70 monitoring
EOF'
/etc/hosts의 변경 내용을 적용하기 위해 network 서비스 재시작
sudo systemctl restart systemd-networkd
빠른 접속을 위해 bastion 머신에서 SSH 인증 키페어 생성
cd ~/.ssh
ssh-keygen -t rsa -b 4096 -f ~/.ssh/bastion_rsa_key
각 서버에 키 복사하기
ssh-copy-id -i ~/.ssh/id_rsa 172.16.0.x
▪ nginx
bastion 서버에서 nginx로 접속
ssh nginx@nginx
1. nginx 설치
sudo apt-get update -y && sudo apt-get install -y nginx
1-1. nginx 설치 확인
sudo apt list --installed | grep "^nginx"
nginx-common/jammy-updates,now 1.18.0-6ubuntu14.4 all [installed,automatic]
nginx-core/jammy-updates,now 1.18.0-6ubuntu14.4 amd64 [installed,automatic]
nginx/jammy-updates,now 1.18.0-6ubuntu14.4 amd64 [installed]
2. nginx 서비스 상태 체크
systemctl status nginx
3. Reverse Proxy 설정
# /etc/nginx/sites-available/default
server {
listen 80;
location / {
proxy_pass http://172.16.0.37:80; # 백엔드 서버 IP / PORT 번호 기입
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
nginx@nginx:~$ cat /etc/nginx/sites-enabled/default
server {
listen 80;
location / {
proxy_pass http://172.16.0.37:80; # 백엔드 서버 IP / PORT 번호 기입
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
3-1. nginx 재시작
sudo nginx -t # nginx 설정 검사
sudo systemctl restart nginx
▪️ web
bastion 서버에서 web로 접속
ssh web@web
1. 프로젝트 clone
git clone https://github.com/JaehyoJJAng/shortenURL
2. Docker Compose 실행
docker-compose up -d --build
2-1. 컨테이너 상태 확인
NAME COMMAND SERVICE STATUS PORTS
redis "docker-entrypoint.s…" redis exited (0)
shorten-app "uvicorn main:app --…" app running 0.0.0.0:80->80/tcp, :::80->80/tcp
▪️ db
bastion 서버에서 db로 접속
ssh db@db
1. MySQL 설치
sudo apt-get update -y && sudo apt-get install -y mysql-server
1-1. mysql 설치 확인하기
sudo apt list --installed | grep "^mysql"
mysql-client-8.0/jammy-updates,jammy-security,now 8.0.35-0ubuntu0.22.04.1 amd64 [installed,automatic]
mysql-client-core-8.0/jammy-updates,jammy-security,now 8.0.35-0ubuntu0.22.04.1 amd64 [installed,automatic]
mysql-common/jammy,now 5.8+1.0.8 all [installed,automatic]
mysql-server-8.0/jammy-updates,jammy-security,now 8.0.35-0ubuntu0.22.04.1 amd64 [installed,automatic]
mysql-server-core-8.0/jammy-updates,jammy-security,now 8.0.35-0ubuntu0.22.04.1 amd64 [installed,automatic]
mysql-server/jammy-updates,jammy-security,now 8.0.35-0ubuntu0.22.04.1 all [installed]
2. MySQL 서비스 체크
systemctl status mysql
3. MySQL 유저 생성
CREATE USER 'jaehyo'@'localhost' IDENTIFIED BY 'jaehyo123';
GRANT ALL PRIVILIGES ON *.* 'jaehyo'@'localhost';
FLUSH PRIVILEGES;
4. DB 생성
CREATE DATABASE jaehyo_db;
5. TABLE 생성
CREATE TABLE jaehyo_tbl (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name TEXT
);
▪️ nfs
bastion 서버에서 nfs로 접속
ssh nfs@nfs
패키지 업데이트
sudo apt-get update -y
nfs에 필요한 패키지 설치
sudo apt-get install -y nfs-common nfs-kernel-server rpcbind
공유 폴더 생성
mkdir -p /share
디렉토리 권한 수정
chmod 707 /share
172.16.0.0/24 대역에서 nfs 서버의 /share 폴더를 마운트 할 수 있도록 /etc/exports 파일에 아래 내용 추가
sudo sh -c 'cat >> /etc/exports << EOF
/share 172.16.0.0/24(rw,sync)
EOF'
nfs-server 재시작
sudo systemctl enable --now nfs-server
sudo systemctl restart nfs-server
변경된 /etc/exports 파일 내용 바로 적용 시키기
exportfs -r
exportfs 적용 내용 출력
exportfs -v
/share 172.16.0.0/24(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,root_squash,no_all_squash)
rpcbind가 사용중인 포트 출력
rpcinfo -p | grep -E 'nfs|mountd'
▪️ 포트 개방
firewall-cmd --permanent --add-service=nfs
firewall-cmd --permanent --add-service=rpc-bind
firewall-cmd --permanent --add-service=mountd
# 방화벽 재시작
firewall-cmd --reload
▪️ RAID 구성
구성표
RAID | 파티션명 | 장치명 | RAID level | 묶을 raid 디바이스 수 |
---|---|---|---|---|
RAID1 | /dev/sdb1 /dev/sdc1 /dev/sdd1 /dev/sde1 |
/dev/md1 | 5 | 4 |
RAID 5 구성방법은 아래 게시글 참고
RAID 5 구성하기 - WTT Devlog
RAID 5 구성 결과
▪️ smb
bastion 서버에서 samba로 접속
ssh samba@samba
samda 패키지 설치
sudo apt-get update && sudo apt-get install -y samba
공유 폴더 생성
mkdir -p /smb-share
디렉토리 권한 수정
chmod 777 /smb-share
samba 접속 유저 생성
# smb 유저 생성
adduser smb
# smb 유저 패스워드 지정
echo "smb:${SMB_PASSWORD}" | chpasswd
# 'smb'라는 이름의 Samba 사용자에 대한 비밀번호를 추가
smbpasswd -a smb
samba 설정 (/etc/samba/smb.conf)
vi /etc/samba/smb.conf
[share]
comment = Share Directory # 설명(주석)
path = /tmp/samba/share # 경로
browserable = yes # yes = 모두가 읽을 수 있음, no = 허가된 사용자만
writable = yes # yes = 모두가 저장할 수 있음, no = 허가된 사용자만
valid users = smb # 인가된 사용자
create mask = 0777 # 파일을 만들면 자동으로 777권한을 부여
directory mask = 0777 # 폴더를 만들면 자동으로 777권한을 부여
samba 서비스 재시작
systemctl enable --now smb.service
systemctl restart smb.service
▪️ 포트 개방
firewall-cmd --permanent --add-service=samba
firewall-cmd --reload
samba 계정 정보를 까먹었다면?
pdbedit
명령으로 조회 가능하다.
sudo pdbedit -L -v
▪️ monitoring
각 서버(web,db ..)들의 journal / systemd 로그들을 Grafana로 가독성 있게 조회하기 위해, 도커 기반 Grafana + Loki + Promtail 조합으로 컨테이너를 올려보도록 하자.
bastion 서버에서 monitoring 서버로 ssh 접속
ssh monitoring@monitoring
1. 사전 준비
1-1) 도커 / Docker Compose 설치하기
도커 설치하기 - WTT Devlog
1-2) /etc/rsyslog.conf 파일 아래 처럼 수정
1-2-1) TCP / UDP 포트 열기 (모니터링 서버에서만 진행)
#### MODULES ####
# ...
# Provides UDP syslog reception
$ModLoad imudp
$UDPServerRun 514
# Provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerRun 514
# ...
1-3) 로그 템플릿 지정하기 ((모니터링 서버에서만 진행)
# ...
$template RemoteLogs, "/var/log/remote/%HOSTNAME%/%$YEAR%-%$MONTH%-%$DAY%_%HOSTNAME%.log"
*.* ?RemoteLogs
#### GLOBAL DIRECTIVES ####
# ...
💥 rsyslog file format
rsyslog.conf에서 로그 파일 포맷을 지정하는 방법에 대해서 자세히 알고싶다면 아래 게시글을 참고하도록 하자.
rsyslog 서버 구축하기 - WTT Devlog
1-4) rsyslog 재시작
sudo systemctl restart rsyslog.service
2. 컨테이너 볼륨 마운트 포인트 생성
mkdir -p "/home/${USER}/loki/config"
chown 10001:10001 "/home/${USER}/loki"
💥 Permission Denied!
loki 디렉토리 소유권을 변경하지 않고 loki 컨테이너를 실행했을 경우 'Permission denied' 라는 오류가 컨테이너 내부에서 발생하며 컨테이너가 실행되지 않음.
3. 공식 홈페이지에서 docker-compose.yaml 파일과 loki-config.yaml, promtail-config.yaml 파일을 다운로드
https://grafana.com/docs/loki/latest/get-started/
cd /home/${USER}/loki
wget https://raw.githubusercontent.com/grafana/loki/v2.2.1/cmd/loki/loki-local-config.yaml \
-O config/loki-config.yaml
wget https://raw.githubusercontent.com/grafana/loki/v2.2.1/cmd/promtail/promtail-docker-config.yaml \
-O config/promtail-config.yaml
wget https://raw.githubusercontent.com/grafana/loki/v2.2.1/production/docker-compose.yaml \
-O docker-compose.yaml
4. loki-config 파일을 사용자의 환경에 맞게 수정
table_manager를 설정하여 2주 정도의 log만 보관하도록 설정하였음.
# /home/${USER}/loki/config/loki-config.yaml
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9096
ingester:
wal:
enabled: true
dir: /tmp/wal
lifecycler:
address: 127.0.0.1
ring:
kvstore:
store: inmemory
replication_factor: 1
final_sleep: 0s
chunk_idle_period: 1h # Any chunk not receiving new logs in this time will be flushed
max_chunk_age: 1h # All chunks will be flushed when they hit this age, default is 1h
chunk_target_size: 1048576 # Loki will attempt to build chunks up to 1.5MB, flushing first if chunk_idle_period or max_chunk_age is reached first
chunk_retain_period: 30s # Must be greater than index read cache TTL if using an index cache (Default index read cache TTL is 5m)
max_transfer_retries: 0 # Chunk transfers disabled
schema_config:
configs:
- from: 2020-10-24
store: boltdb-shipper
object_store: filesystem
schema: v11
index:
prefix: index_
period: 24h
storage_config:
boltdb_shipper:
active_index_directory: /tmp/loki/boltdb-shipper-active
cache_location: /tmp/loki/boltdb-shipper-cache
cache_ttl: 24h # Can be increased for faster performance over longer query periods, uses more disk space
shared_store: filesystem
filesystem:
directory: /tmp/loki/chunks
compactor:
working_directory: /tmp/loki/boltdb-shipper-compactor
shared_store: filesystem
limits_config:
reject_old_samples: true
reject_old_samples_max_age: 168h
chunk_store_config:
max_look_back_period: 0s
table_manager:
retention_deletes_enabled: false
retention_period: 0s
ruler:
storage:
type: local
local:
directory: /tmp/loki/rules
rule_path: /tmp/loki/rules-temp
alertmanager_url: http://localhost:9093
ring:
kvstore:
store: inmemory
enable_api: true
5. promtail-config 파일을 사용자의 환경에 맞게 수정
syslog receive와 journal / static log를 수집하도록 설정
# /home/${USER}/loki/config/promtail-config.yaml
# cat /loki/config/promtail-config.yaml
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push # loki_컨테이너_이름:포트번호
scrape_configs:
- job_name: all_logs
static_configs:
- targets:
- localhost
labels:
job: all_logs
__path__: /var/log/remote/*/*log
- job_name: syslog
syslog:
listen_address: 0.0.0.0:1514
labels:
job: "syslog"
relabel_configs:
- source_labels: ["__syslog_connection_ip_address"]
target_label: "ip_address"
- source_labels: ["__syslog_message_severity"]
target_label: "severity"
- source_labels: ["__syslog_message_facility"]
target_label: "facility"
- source_labels: ["__syslog_message_app_name"]
target_label: "app_name"
- source_labels: ["__syslog_message_hostname"]
target_label: "host"
- job_name: journal
journal:
max_age: 12h
labels:
job: systemd-journal
relabel_configs:
- source_labels: ["__journal__systemd_unit"]
target_label: "systemd_unit"
- source_labels: ["__journal__hostname"]
target_label: "nodename"
- source_labels: ["__journal_syslog_identifier"]
target_label: "syslog_identifier"
💡 path
모니터링 서버의 /etc/rsyslog.conf 파일에서 설정했던 경로를 지정해주면 된다. 모니터링 서버에 로그가 수집되는 path를 지정해주면 된다.
💡 clients.url
해당 주소에서 사용되는http://loki:3100..
이 주소는 loki 컨테이너의 이름과 loki 컨테이너 내부 포트를 지정한 것이다.
loki 서버가 도커가 아닌 외부 물리 서버 또는 가상 서버로 설치된 경우 해당 서버의 IP와 포트번호를 지정해주면 된다.
6. docker-compose.yaml 파일을 아래 내용과 같이 만들어주자.
호스트의 /home/${USER}/loki 경로에 모든 data가 수집될 수 있도록 마운트 경로를 지정해줬음.
# cat docker-compose.yaml
version: "3.8"
services:
loki:
image: grafana/loki
restart: always
volumes:
- type: bind
source: '/home/${USER}/loki/config'
target: '/mnt/config'
- type: bind
source: '/home/${USER}/loki'
target: '/loki'
ports:
- "3100:3100"
command: -config.file=/mnt/config/loki-config.yaml
container_name: gafana-loki
networks:
- 'loki-net'
promtail:
image: grafana/promtail
restart: always
ports:
- "1514:1514"
volumes:
- type: bind
source: '/var/log'
target: '/var/log'
- type: bind
source: '/home/${USER}/loki/config'
target: '/mnt/config'
- type: bind
source: '/var/log/journal/'
target: '/var/log/journal/'
- type: bind
source: '/run/log/journal/'
target: '/run/log/journal/'
- type: bind
source: '/etc/machine-id'
target: '/etc/machine-id'
command: -config.file=/mnt/config/promtail-config.yaml
container_name: loki-promtail
networks:
- 'loki-net'
grafana:
container_name: grafana
image: grafana/grafana
ports:
- "3000:3000"
volumes:
- type: volume
source: "grafana-db"
target: "/var/lib/grafana"
networks:
- 'loki-net'
volumes:
grafana-db: {}
networks:
loki-net:
driver: bridge
external: false
7. 컨테이너 실행
docker-compose up -d --build
▪️ 포트 개방
sudo firewall-cmd --permanent --add-port=3000/tcp
sudo firewall-cmd --permanent --add-port=3100/tcp
sudo firewall-cmd --permanent --add-port=1514/tcp
sudo firewall-cmd --reload
◾️ 운영 테스트
▪️ web
외부망 브라우저에서 192.168.219.5:80 입력하여 nginx에서 fastapi app으로 reverse proxy가 잘 작동하는지 테스트
▪️ nfs
bastion 서버에서 web 서버로 ssh 접속
ssh web@web
nfs 설치
sudo apt-get install -y nfs-common
nfs 서버에서 활성화된 공유 디렉토리 목록 출력
(nfs 서버 IP : 172.16.0.66)
showmount -e 172.16.0.66
web 서버에서 공유 폴더 생성
# web
mkdir -p /web-share
nfs 서버의 /share 폴더로 마운트
mount -t nfs 172.20.0.10:/share /web-share
마운트 됐는지 체크
# web
df -h | grep "^172.20.0.10"
/etc/fstab에 마운트 정보 등록
vim /etc/fstab
...
172.16.0.66:/share /web-share nfs defaults 0 0
▪️ samba
윈도우 10에서 samba를 이용한 파일 공유 테스트를 진행.
검색창에 \\[samba 서버 주소]
"로 검색
조금 전에 생성했던 삼바 계정으로 로그인 (smb / ****)
정상적으로 로그인 되었음.
새로운 텍스트 파일을 하나 만들어보자.
samba 서버의 터미널로 이동 한 후에, 윈도우에서 생성한 hello_jaehyo 텍스트 파일이 /smb-share 디렉터리에 있는지 확인해보자.
▪️ monitoring
로그를 수집할 클라이언트 서버로 원격 접속하자.
ssh nginx@nginx # web,db,nfs,samba 서버에서도 아래 내용 동일하게 진행
1. /etc/rsyslog.conf 파일에 아래 내용을 추가해주자.
중괄호 안에는 위에서 설장한 로그를 받는 서버의 IP 기입
* 아래 코드중 ‘@’ 한개는 UDP, ‘@@’ 두개는 TCP를 사용하겠다는 의미
# /etc/rsyslog.conf
# ...
*.* @{IP}:514
#### GLOBAL DIRECTIVES ####
# ...
2. rsyslog 재시작
sudo systemctl restart rsyslog
3. 모니터링 서버로 다시 원격접속하여 /var/log/remote 디렉토리 내에 각 클라이언트 서버들의 hostname들이 생성되었는지 확인
sudo ls -lh /var/log/remote
4. 외부망 PC에서 브라우저 주소 http://192.168.219.170:3000
로 접근
192.168.219.170
: 라우터의 외부 인터페이스 주소- 라우터에 역방향 NAT가 설정된 상태여야함.
192.168.219.170:3000 -> 172.16.0.70:3000
:3000
: docker proxy로 외부에 오픈된 그라파나 컨테이너 외부 포트 주소 (내부 컨테이너 포트가 아님)
초기 로그인 정보: admin/admin
5. Data Source에 Loki 추가
💥 URL 주소
http://<로키 컨테이너명>:3100
Explore 탭 이동 - Label filters 지정 후 로그 모니터링