배경

회사에서 이미 rootful로 구축된 서비스를 rootless로 전환하는 업무를 담당하게 되었다. 그래서 로컬의 virtual box에서 rocky8.4로 rootless docker를 설치하는 실습을 진행해본 후, 최대한 실제 운영 환경과 유사하게 테스트를 진행하기 위해 팀 내부의 GPU 서버에서 다시 동일한 작업을 진행하게 되었다. rootless 도커 설치 과정 포스팅은 여기를 참고 바란다. 

 

그런데 dockerd-rootless-setuptools.sh install을 진행할 때, rocky에서는 문제 없이 진행이 되었으나 centOS에서는 systemd not detected 라는 에러가 표시됐다. 그래서 우선 내 상황에서는 아래 2가지를 고려해야 했다. 

1. rocky8.4(virtual box test 환경)와 redhat8.4(작업 대상 운영 서버)에서는 항상 동일한 결과를 기대할 수 있을까?

2. CentOS에서도 rootless docker를 적용하는 방법은?

 

rocky linux의 공식 홈페이지를 보면 Rocky Linux is an open-source enterprise operating system designed to be 100% bug-for-bug compatible with Red Hat Enterprise Linux. 라고 하니 1번은 걱정하지 않아도 될 것 같다. 그럼 이제 centos에서 테스트를 진행하는 방법을 찾아보도록 하자.

 

트러블슈팅

아래는 내가 시도해본(그러나 실패한) 방법들이며, 최종적으로는 setuptools가 아닌 일반 sh파일을 실행해서 적용했다. 결론만 보고 싶다면 더 아래쪽 내용을 참고 바란다. 

[systemd란?]
Systemd 는 기존 리눅스 시스템에서 사용해왔던 init script 를 대체한다. 배포판마다 적용된 버전이 다른데, CentOS에 경우에는 7 버전부터 적용되기 시작했다. Systemd 는 부팅과정에서 최초로 실행되는 프로세스이며 리눅스 시스템 전체를 움직하게 하는 프로세스이다. 이 프로세스는 또 다른 프로세스들을 제어하는데 이를 위해서 systemd 프로그램을 제공한다.부팅과정에서 자동으로 데몬들을 실행시키는 것도 systemd 가 하는데 이 프로그램은 데몬에 대한 명세서인 unit 파일을 기반으로 실행을 시켜준다. 이러한 파일들은 전역 시스템 영역에 속한다.
출처: https://linux.systemv.pe.kr/linux/systemd-user-사용하기/

 

정리해보자면 rootless docker 설정 시 systemd가 detected되지 않는다는 메세지가 출력됐고(사실 [INFO]라고 출력되어서 나중에서야 알았다), systemctl --user start docker 시에는 Failed to get D-Bus connection: No such file or directory 에러가 발생하고 있는 상황이었다. DBUS 관련 에러를 먼저 찾아보니, 해당 에러는 사용자 세션용 D-Bus 연결을 찾을 수 없을 때 발생한다고 한다. echo로 확인해보니 DBUS_SESSION_BUS_ADDRESS 환경변수도 없어서, 해당 변수를 설정하고 수동으로 세션을 실행하면 되지 않을까? 라고 생각했다.

# 사용자 전용 세션 DBUS를 실행함
mkdir -p $XDG_RUNTIME_DIR/dbus
# 백그라운드로 실행하고 주소를 반환함
dbus-daemon --session --address=unix:path=$XDG_RUNTIME_DIR/dbus/user_bus_socket --fork --print-address
# 사용자 단 systemd 서비스 등에서 DBUS를 사용할 수 있게 환경 변수 설정
export DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/dbus/user_bus_socket

 

위 설정 이후 systemdctl --user start docker를 다시 실행해 보았는데 Failed to start docker.service: Process org.freedesktop.systemd1 exited with status 1. See system logs and ‘systemctl status docker.service’ for details 에러가 표시됐다. centos에서 systemctl --user를 사용하는 방법에 대해서 찾아보며 이 블로그를 보고 systemd-pam 관련 설정도 따라해봤지만, 잘 되지 않았다. (다른 OS에서는 될 수도 있다)

 

그러다가 CentOS는 systemd user 모드를 지원하지 않는다는 글을 발견했다..!

 

해결

그래서 검색 키워드를 바꿔, 에러 내용이 아니라 CentOS에서 rootless를 설정하는 방법을 구글링해 보았고 이 글을 찾을 수 있었다. (2018년 글인데, 그만큼 내가 지금 쓰려는 OS가 오래됐다는 거겠지.. 아무리 개발 서버라지만 최소한 8버전으로 올려줬음 좋겠다.)

[root@dlp ~]# echo "cent:100000:65536" > /etc/subuid
[root@dlp ~]# echo "cent:100000:65536" > /etc/subgid
[root@dlp ~]# cat /etc/subgid /etc/subgid

# 블로그 명령어
[cent@dlp ~]$ /usr/bin/dockerd-rootless.sh &
# 세션 종료 시에도 실행하는 명령어
[cent@dlp ~]$ nohup /usr/bin/dockerd-rootless.sh > dockerd.log 2>&1 &

 

우선 dockerd-rootless-setuptools.sh 대신 일반 dockerd-rootless.sh 파일을 실행해야 한다. system가 지원되지 않는 환경이기 때문에 직접 데몬을 실행하는 방식이다.

  • setuptools sh파일: systemd 기반의 자동 관리. user mode-systemd 지원 필요
  • 일반 sh 파일: systemd에 의존하지 않고 직접 터미널에서 데몬을 실행

 

그리고 subuid 및 gid를 설정하는 부분이 있는데, setuptools 파일에는 해당 설정을 하는 부분이 포함되어 있으나 일반 쉘 파일에는 없기 때문에 추가로 실행해줘야 한다. 해당 명령어는 사용자 계정의 subuid, gid를 설정하는 것으로, /etc/subuid 및 gid 파일에 관련 데이터를 저장한다. 단, 이미 다른 계정에 할당되어 있는 id는 중복 할당이 불가능하므로, 범위 조정이 필요할 수 있다. 관련 설정은 공식 문서에서도 찾아볼 수 있다. 

  • cent: 사용자 계정
  • 100000: 시작 UID/GID
  • 65536: 할당할 uid, gid 범위(개수)

 

마지막으로, 블로그에는 단순히 “&”를 통해 백그라운드로만 실행을 했지만, 실제 도커 서비스를 운영하고자 하는 경우에는 세션이 종료되어도 서비스는 계속해서 실행되어야 한다. 이를 위해 나는 nohup으로 데몬을 실행시켰고, 로그 파일을 별도로 저장하도록 했다.(이를 고려하긴 했지만 실제로 그런 상황에서 잘 서비스되는지는 확인하지 못했다.) 그 결과 rootless 모드로 도커가 실행되는 것을 확인할 수 있었다. ps -ef | grep dockerd 실행 시 프로세스가 root가 아니라 일반 계정으로 실행되고 있다면 성공한 것이다. 

배경

관계사 서버에 솔루션 구축과 함께 docker 설치를 처음부터 해야 할 일이 생겼다. 그래서 팀 내 개발 서버들에 설정되어 있던 daemon.json 파일의 속성들을 종합하여 무얼 위한 설정인지 검토해보게 되었다. 내 경우 GPU를 사용해야 해서 runtime을 설정하는 부분이 필수적이었다. 

 

속성 분석

{
	"default-runtime": "nvidia",
	"runtimes": {
		"nvidia": {
			# NVIDIA에서 제공하는 실행 파일. GPU를 사용할 수 있도록 도커와 NVIDIA 드라이버를 연결해줌
			"path": "nvidia-container-runtime",
			# 기본적으로 빈 배열. 필요 시 인자 추가
			"runtimeArgs": []
		}
	}
	"exec-opts": ["native.cgroupdriver=systemd"]
	"log-driver": "json-file"
	"log-opts": {
		"max-size": "100m"
	}
	"storage-driver": "overlay2"
	"icc": false
	"data-root": "/disk/docker"
	"insecure-registries": ["x.x.x.x:10000"]
}
  • default-runtime
    • 도커가 컨테이너 실행 시 사용하는 기본 런타임 지정
    • "runc"가 기본, GPU 지원 컨테이너 실행 시에는 "nvidia" 필수
    • "nvidia" 지정 시에는 runtimes 블록 안에 정의되어 있어야 해당 런타임 인식 가능. 없으면 unknonwn runtime 에러 발생
    • 참고로, nividia 관련 파일은 which nvidia-container-runtime 명령어를 통해 toml 파일의 위치를 찾을 수 있음
  • exec-opts
    • 도커가 사용하는 cgroup 관리 방식 지정
    • cgroupfs가 기본값, systemd가 권장값(특히 쿠버 환경에서)
    • 도커가 시스템 자원을 컨테이너에 할당할 때 사용하는 cgruop 방식에 영향
  • log-driver
    • 도커 컨테이너의 로그 저장 방식을 지정
    • "json-file"이 기본값
  • log-opts
    • 로그 파일의 크기 제한을 설정
    • 일정 크기 초과 시 순환 로그 시작
  • storage-driver
    • 도커가 이미지와 컨테이너 파일 시스템을 저장하는 방식
    • overlay2가 대부분의 최신 리눅스 배포판에서 제일 빠르고 효율적
    • 이외에도 fuse-overlayfs, vfs 등이 있음
  • icc
    • Inter-Container Communication 허용 여부
    • false로 설정 시 같은 도커 브리지 네트워크 간 통신을 차단함
  • graph / data-root
    • 도커의 컨테이너 이미지, 볼륨, 레이어 등을 저장하는 기본 디렉토리 경로
    • graph는 옛날 도커 버전에서 사용되던 속성으로, 현재는 data-root로 변경됨
    • "/var/lib/docker"가 기본값이나, 별도 디스크 사용 시 변경 가능
  • insecure-registries
    • 도커는 기본적으로 HTTPS를 사용해 이미지 registry와 통신
    • 해당 속성은 HTTP 또는 자체 서명된 HTTPS 레지스트리를 예외적으로 허용

네트워크와 인터넷 서비스

네트워크의 개요

네트워크: 전송 매체(링크)로 연결되어 데이터를 상호 교환하는 시스템(노드)들의 그룹

LAN이라는 것은 여러 호스트가 같은 장비를 공유해서 사용한다. 그 과정에서 충돌이나 병합 문제가 발생하게 되는데, 이를 제어하기 위한 기술을 매체 접근 제어 방식이라고 한다. 
-CSMA/CD(Carrier sense multiple access/collision detection): 단말기가 전송로의 신호 유무를 조사하고 다른 단말기가 신호를 송출하는지 확인(통신 전 충돌 방지를 위해 점검)
- Token Passing: 토큰의 흐름에 따라 전송 순서가 결정됨. 사용 시 토큰 값을 변경하여 사용 여부를 알림
  • LAN(Local Area Network): 사무실, 학교 등 지리적으로 한정된 범위의 근거리 통신망(10 km 이내)
    • LAN 구성 방식
      • Ethernet: CSMA/CD 방식 사용
      • Token Ring: Token Passing 방식 사용
      • FDDI: 이중 링, Token Passing 방식 사용
  • MAN(Metropolitan Area Network): 도시 지역을 잇는 통신, LAN을 연결한 백본라인
    • MAN 구성 방식
      • 광섬유, 동축 케이블
      • DBQB(Distributed Queue Dual Bus): 회선 교환/패킷 교환. DBQB는 QPSX(Queued Packet Synchronous Exchange) 접속 제어에 사용
  • WAN(Wide Area Network): 국가, 대륙 등 넓은 지역의 네트워크
    • 거리 제한이 없고 다양한 경로를 지원
    • 상대적으로 속도가 느리고 에러율이 높음
    • WAN 구성 방식
      • 전용선, 회선교환망, 패킷 교환망
  • SAN(Storage Area Network): 스토리지 구성을 위한 고속 전용 네트워크
    • 여러 개의 저장 장치를 Fiber Channel(광채널)로 연결하여 가상화된 스토리지 영역을 만듦
    • 호스트의 종류에 구애받지 않고 대용량의 데이터를 전송시킬 수 있는 고속 네트워크
    • 파일 I/O 요청을 블록 I/O로 전환 후 SAN 스토리지로 전달

 

네트워크 교환 방식

  • 회선 교환 방식(Circuit Switching Network)
    • 송수신 단말장치 사이에서 연결 경로를 미리 설정 후 데이터 전송
  • 메세지 교환 네트워크(Message Switch Network)
    • 메세지 헤더에 목적지 주소를 표시하여 전송
    • 사전 경로 설정 없음
    • 교환기가 전송자의 메세지를 받은 후 수신자 확인 및 전달
  • 패킷 교환 네트워크(Packet Switching Network)
    • 메세지를 일정 크기의 패킷으로 분할하여 전송
    • 교환기는 패킷의 목적지 주소를 참고하여 전송 경로 선택
    • 가상회선과 데이터그램 방식 사용

 

LAN 토폴로지(Topology)

  • 호스트 및 장비들의 물리적인 배치 형태를 의미

 

네트워크 장비

 

 


네트워크 계층

OSI 7계층과 TCP/IP 모델

 

계층별 프로토콜

  • 프로토콜: 컴퓨터 네트워크에서 데이터 교환 방식을 정의한 규악, 주고받는 데이터 형식 및 수행 절차
  • 프로토콜의 구성 요소

  • 응용 계층 프로토콜
    • SMTP, POP: 메일 주고받을 때 사용
    • Telnet: 원격으로 접속해서 명령어를 주고받음
    • SSH: 암호화된 형식으로 제어 코드를 주고받음
    • FTP: 파일 업로드, 다운로드에 최적화
    • TFTP: 임베디드 시스템에서도 사용 가능하도록 함
    • HTTP: 웹 서비스의 근간
    • SNMP: 네트워크를 모니터링하고 제어할 때 사용
    • DHCP: IP 주소를 자동 할당
  • 전송 계층 프로토콜
    • TCP(Transmission Control Protocol): 신뢰성, connection oriented 방식
    • UDP(User Datagram protocol): 단순한 헤더 구조, 빠른 속도
  • 인터넷/네트워크 계층 프로토콜
    • IP: 논리 주소 기반 통신
    • ICMP: IP통신의 오류 등을 보완한 것
    • IDMP: 그룹과 관련
    • ARP, RARP: IP주소와 MAC 주소의 변환을 관리

 


IP 주소와 도메인

IPv4 주소체계

  • 4개의 옥텟으로 구성되며, 각 옥텟은 8bit, 총 32bit임
  • E 클래스의 240~255 대역은 IP 주소의 부족을 위해 예약해놓은 것
  • IP 주소는 네트워크 ID + 호스트 ID로 구성되며, subnet mask로 네트워크/호스트 부분을 구분함

 

서브넷팅

  • 특정 네트워크를 여러 개의 네트워크, broadcast 도메인을 나누는 것
  • IP 주소의 부족 현상을 해소하기 위한 방안
  • 디폴트 서브넷 마스크를 기준으로 하여 네트워크 ID bit수를 늘리고 호스트 ID bit수를 줄이는 것
  • 이때 기준에서 늘어난 네트워크 ID bit는 서브넷ID라고 부름

 

특수 네트워크 주소

  • Network 주소: 호스트 비트가 모두 0
  • Direct Broadcast 주소: 호스트 비트가 모두 1(255값)
  • Limited Broadcast: 255.255.255.255, DHCP 클라이언트가 DHCP 서버를 찾을 때 사용
  • Lookback 주소: 127.0.0.0~127.255.255.255, 내부 시험 테스트용
  • 0.0.0.0: 자신의 IP를 모를 경우(부팅 시)에 사용

 

IPv6 주소체계

  • 기존 IPv4의 주소가 부족할 것을 대비하여 만들어진 차세대 주소
  • 총 128bit로, 16진수 8자리가 “:”로 구분됨

 

 


인터넷 서비스의 종류

www(world wide web)

  • HTTP를 기반으로 한 서비스
  • 분산 클라이언트-서버 모델
  • HTTP: Request(GET, POST), Response(응답 코드), Header+Body(Data)
  • 표준 웹 프로토콜(HTTP, XML, SOAP, USDL, UDDI)를 기반으로 하여 서로 다른 개발 환경과 운영체제에서도 상호 통신 가능

 

FTP 서비스

  • TCP/IP 기반, 파일 복사/전송에 최적화
  • 통신 모드: 액티브 모드, 패시브 모드로 구분
  • FTP는 20번(일반 데이터 전송용)과 21번(제어 데이터 전송용) 포트를 사용함

  • 계정 정책: 사용자 계정, 익명 계정 허용

 

DNS 서비스(Domain Name System)

  • 호스트(도메인)이름 ↔ IP 주소 맵핑
  • 도메인명을 분산된 트리 형태의 계층적 구조로 관리
  • DNS 레코드 관리
    • A: IPv4 주소 기술
    • AAA: IPv6 주소 기술
    • MX: 메일 서버 관련
    • TXT: 일상 정보 담음
    • SOA: 관리 정보 담음
    • PTR: 역변환(IP주소를 도메인으로 바꿈)
    • CNAME: 별칭 부여

 

Telnet과 SSH

  • 공통점: 원격으로 로그인하여 실행 명령을 보내 제어 가능
  • 차이점
    • Telnet: Byte 스트림 형식으로 전송
    • SSH: RSA 등 암호화 기법을 사용하여 전송, 압축 기술도 제공

 

NFS(Network File System)

  • 파일 공유를 위한 클라이언트/서버 방식 프로그램
  • 원격지에 있는 리눅스 서버의 특정 디렉터리를 로컬 시스템의 하위 디렉터리처럼 사용 가능
  • 다른 컴퓨터의 파일 시스템을 마운트하고 공유함
  • portmap 데몬을 이용한 RPC 연결 사전 필요
  • NFS 관련 데몬: nfsd, rpc.mounted, rpc.rockd, rpc.rquotad 등

 

RPC(Remote Procedure Call)

  • 동적으로 서비스와 포트를 연결할 때 사용
  • 일반적으로는 정적 할당 방식을 많이 사용(/etc/services 참조)
  • 동적으로 포트를 할당받기 위해서는 RPC의 rpcbind 사용(SUN은 sunrpc)

 


인터넷 서비스의 설정

네트워크 인터페이스 설정

  • 리눅스는 다양한 네트워크 인터페이스를 지원함
  • 일반적으로는 자동으로 인식되지만, 안될 경우 수동으로 설정 필요
  • 수동 방식은 컴파일된 인터페이스 모듈을 커널에 적재하는 것
  • → 자동 적재와 수동 적재 존재

 

네트워크 설정 파일들

  • /etc/sysconfig/network: 네트워크의 기본 정보가 설정되어 있음
  • /etc/sysconfig/network-scripts/ifcfg-ethX: 지정된 네트워크 인터페이스의 환경 설정 정보
  • /etc/resolv.conf: 기본 도메인명, 네임 서버를 설정
  • /etc/hosts: IP 주소와 도메인 주소를 1:1로 등록
  • /etc/host.conf: DNS 서비스를 제공할 때 먼저 이 파일을 검사하여 파일의 설정에 따라 서비스함

 

IP 주소 설정 방법

  • 설정 파일: /etc/sysconfig/network, /etc/sysconfig/network-scripts/ifcfg-ethX
  • 명령어: ifconfig
  • 유틸리티: netconfig, system-config-network, redhat-config-network 등

 

라우팅 테이블 설정 및 관리

  • 라우팅이랑 송신 패킷이 목적지까지 전송할 수 있도록 경로를 설정하는 작업
  • route 명령어를 통해 라우팅 테이블을 설정하거나 확인 가능

 

네트워크 관련 명령어

 

 


리눅스 기술 동향과 활용

리눅스 기술 동향

  • 리눅스는 기본적으로 POSIX와 인터넷 프로토콜 포준 등 국제 표준을 따르고 있음
  • 초기 리눅스는 주로 서버로 이용
  • 현재는 크게 서버, 데스크톱 및 개발, 임베디드 분야에 사용
  • 최근에는 클라우드에서의 중요성도 대두됨

리눅스 관련 기술

  • 클러스터링
    • 여러 개의 시스템이 하나의 거대한 시스템으로 보이게 만드는 기술
    • 종류: 고계산용, 부하 분산, 고가용성(HA)
  • 임베디드 시스템
    • HW와 SW가 통합된 특정 목적을 수행하는 컴퓨팅 시스템
    • 실시간 처리 지원, 높은 신뢰성 보장, 소형/경량/저전력을 지원
  • 서버 가상화
    • 하나의 물리적 호스트에서 여러 OS 실행
    • 가상화 기술을 기반으로 한 IT 인프라 활용성 향상(가용성)
  • 클라우드 컴퓨팅
    • 가상화 기술을 기반으로 IT 자원 및 서비스 제공
    • On demend 방식(필요한 만큼만 사용)
    • 서비스 종류
      • IaaS(Infra Structure as a Service): 서비스나 스토리지같은 하드웨어 자원만을 임대
      • PaaS(Platform as a Service): 소프트웨어 서비스를 개발하기 위한 플랫폼을 제공
      • Saas(Software as a Service): 클라우드 환경에서 동작하는 응용 프로그램을 서비스 형태로 제공
    • 클라우드 서비스 모델: 사설(Public), 공용(Public), 하이브리드(Hybrid)
    • 구축 환경: openstack, cloud stack, 유칼립투스(Eucalyptus)
  • 빅데이터
    • 대규모 데이터로부터 저렴한 비용으로 가치를 추출하고 데이터의 빠른 수집, 발굴 분석을 지원
    • 3개 요소: 볼륨(volume), 속도(velocity), 다양성(variety)
  • 스마트 TV
    • 인터넷과 서비스가 통합된 TV
  • IVI(In Vehicle Infortainment)
    • 정보(Information)+오락(Entertainment)
    • 운전자의 편의성과 안정성을 지원

References

접근

전형적인 BFS 문제였다. 가로 세로의 길이가 50 이하로, 모든 경우를 탐색한다 해도 2500번만 보면 된다. 모든 칸을 탐색하며 육지일 경우 bfs로 가장 긴 거리를 리턴하고, 그 중 가장 큰 수를 출력하면 된다.

개인적으로 하나로 연결된 육지를 계속해서 확인해봐야 한다는 점이 비효율적으로 느껴져 개선 방안을 찾아보고자 했지만.. 다른 사람들의 풀이를 참고해봐도 실행 시간이 비슷한 것으로 보아 특별한 해결책은 찾지 못했다. 

 

코드

import java.util.*;
import java.lang.*;
import java.io.*;

class Main {
    static int[] dx = {-1, 0, 1, 0};
    static int[] dy = {0, 1, 0, -1};
    static char[][] map;

    public static class Pos{
        int x;
        int y;
        int dist = 0;

        Pos(int x, int y, int d){
            this.x = x;
            this.y = y;
            this.dist = d;
        }
    }
    
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        // 입력값 저장
        int h = Integer.parseInt(st.nextToken());
        int w = Integer.parseInt(st.nextToken());
        map = new char[h][w];

        for(int i = 0; i < h;i++)
            map[i] = br.readLine().toCharArray();

        // 최단거리 계산
        int answer = solve(w, h);
        System.out.println(answer);
    }

    public static int solve(int w, int h){
        int res = 0;

        for(int i = 0;i < h;i++){
            for(int j = 0;j < w;j++){
                if(map[i][j] =='W') continue;
                int curMax = bfs(i, j, w, h);
                res = Math.max(res, curMax);
            }
        }
        
        return res;
    }

    public static int bfs(int x, int y, int w, int h){
        int maxDist = 0;
        
        boolean[][] visit = new boolean[h][w];
        for(int i = 0;i < h;i++)
            Arrays.fill(visit[i], false);

        Queue<Pos> q = new LinkedList();
        q.add(new Pos(x, y, 0));
        visit[x][y] = true;
        
        while(!q.isEmpty()){
            Pos cur = q.poll();
            maxDist = Math.max(maxDist, cur.dist);

            for(int d = 0;d < 4;d++){
                int nx = cur.x + dx[d];
                int ny = cur.y + dy[d];

                // 범위를 벗어남
                if(!inBound(nx, ny, w, h)) continue;
                // 바다이거나 이미 방문함
                if(map[nx][ny] == 'W' || visit[nx][ny]) continue;

                q.add(new Pos(nx, ny, cur.dist+1));
                visit[nx][ny] = true;
            }
        }

        return maxDist;
    }

    public static boolean inBound(int x, int y, int w, int h){
        return !(x < 0 || x >= h || y < 0 || y >= w);
    }
}

 

'Algorithm' 카테고리의 다른 글

[백준] 5430: AC JAVA  (0) 2025.05.18
[백준] 1092: 배 JAVA  (0) 2025.03.02
[백준] 1976: 여행 가자 JAVA  (0) 2025.03.01
[백준] 11403: 경로 찾기 JAVA  (0) 2025.02.28
[백준] 9084: 동전 JAVA  (0) 2025.02.14

접근

어렵진 않은데, 생각보다 푸는 데 되게 오래 걸렸던 문제다. 구현 문제는 알고리즘에 조금 소홀해지면 바로 표가 나는 것 같다. 

 

1. 우선 처음에는 'R' 명령어가 나올 때마다 배열을 reverse하는 단순한 방식으로 작성했고, 시간초과가 났다.

2. 그래서 R이 나올 때마다 flag값을 반전시켜 앞/뒤쪽 중 어디에서 아이템을 삭제할지 정하는 방식으로 수정했다. 

3. 이번엔 시간 초과는 안났는데, 틀렸다. 질문 게시판의 반례를 모두 입력해보아도 틀린 경우가 없었는데.. 

4. 이유가 다소 어이없었다ㅠ 내가 작성한 코드의 ArrayList.toString() 함수는 "[1, 2, 3]"과 같이 각 값 사이에 공백이 추가되어 나오는데, 문제의 테스트 케이스는 "[1,2,3]"과 같이 공백이 없는 값을 요구하고 있었다.. 그래서 replaceAll로 공백을 모두 없애주니 통과했다. 

 

다른 사람들의 코드와 비교해봤을 때 실행 시간이 다소 느린 것 같아서 그 이유를 고민해봤다. 로직은 동일한데, 자료구조의 문제였던 것 같다. 내가 사용한 ArrayList는, 만약 첫 번째 아이템을 remove한다면 뒤쪽의 아이템들을 모두 앞당기는 과정이 필요하다고 한다.(by gpt) 그런데 676ms가 나온 해당 코드를 보면 Deque를 사용하고 있다. 디큐도 잘 알고 있는 자료구조였지만, 알고리즘 문제를 풀며 자주 접하게 되지는 않다보니 이를 사용할 생각을 못한 것 같다. 

 

코드

import java.util.*;
import java.lang.*;
import java.io.*;

class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        
        int tc = Integer.parseInt(br.readLine());
        for(int t = 0;t < tc;t++){
            // 입력값 저장
            char[] p = br.readLine().toCharArray();
            int n = Integer.parseInt(br.readLine());
            String[] numStrArr = br.readLine().split(",|\\[|\\]");  // 양 끝에는 빈 리스트가 올 것
            
            // 숫자 배열 전처리
            ArrayList<Integer> numArr = new ArrayList();

            for(int i = 0;i < n;i++)
                numArr.add(Integer.parseInt(numStrArr[i+1]));

            String res = solve(p, numArr);
            sb.append(res).append("\n");
        }
        
        System.out.println(sb.toString());
    }

    public static String solve(char[] commandArr, ArrayList<Integer> numArr){
        // 첫 번째 코드(시간 초과)
        /**
        int commandCnt = commandArr.length;
        for(int i = 0;i < commandCnt;i++){
            char c = commandArr[i];
            if(c == 'R'){
                Collections.reverse(numArr);
            }
            else {  // c == 'D'
                if(numArr.size() == 0)
                    return "error";
                else
                    numArr.remove(0);
            }
        }

        return numArr.toString();
        **/

        int commandCnt = commandArr.length;
        boolean reverseFlag = false;
        
        for(int i = 0;i < commandCnt;i++){
            char c = commandArr[i];
            if(c == 'R'){
                reverseFlag = !reverseFlag;
            }
            else {  // c == 'D'
                if(numArr.size() == 0)
                    return "error";
                else{
                    if(reverseFlag)
                        numArr.remove(numArr.size()-1);
                    else
                        numArr.remove(0);
                }
            }
        }

        if(reverseFlag)
            Collections.reverse(numArr);

        return numArr.toString().replaceAll(" ", "");
    }
}

'Algorithm' 카테고리의 다른 글

[백준] 2589: 보물섬 JAVA  (0) 2025.05.20
[백준] 1092: 배 JAVA  (0) 2025.03.02
[백준] 1976: 여행 가자 JAVA  (0) 2025.03.01
[백준] 11403: 경로 찾기 JAVA  (0) 2025.02.28
[백준] 9084: 동전 JAVA  (0) 2025.02.14
Jasypt 활용 목적
우리 솔루션은 .env 파일에 변수를 따로 정리해 두고, docker-compose.yml 파일에서 참조하여 사용하고 있다. 이 .env 파일에 적혀있는 DB 패스워드값이 평문이기 때문에 이를 암호화하고자 한다. 임의의 secretKey를 지정하여 해당 패스워드를 암호화하고, 이를 .env파일에 넣으면 된다.

 

 

jasypt 설치

라이브러리 종류

나는 폐쇄망에서 개발 중이었기 때문에, 인터넷에서 jar 파일을 다운로드하여 반입해야 한다. 그 과정에서 jasypt 라이브러리의 타입이 다양해서 처음에는 무엇을 설치해야 할지 헷갈렸다.

우선 공식 git 레포지토리를 찾아보면 두 가지가 나온다. (jaspyt 깃허브 & jasypt spring boot 깃허브) 전자는 일반 jasypt 라이브러리에 대한 페이지이며 후자는 spring boot와의 통합을 위한 라이브러리에 해당한다. 즉 나는 스프링 코드에 사용할 것이기 때문에 후자를 다운로드 하면된다.

이제 jar 파일 다운로드를 위해 maven central repository “jasypt spring boot”를 검색했다. 그랬더니 일반 jasypt spring boot와 jasypt spring boot starter가 있었다. Jasypt Spring Boot는 asypt를 Spring Boot 애플리케이션에서 사용할 수 있게 해주는 기본 라이브러리이며, starter는 Jasypt Spring Boot를 Spring Boot 애플리케이션에 통합하기 쉽게 만든 스타터 라이브러리이다. pring Boot의 starter는 Spring Boot 애플리케이션에서 특정 라이브러리를 더 쉽게 사용할 수 있도록 도와주는 구성요소이다.

 


기본 설정 변경

gradle 설정

build.gradle 파일에서 해당 라이브러리를 사용하고자 하는 모듈에 아래와 같이 implementation 을 추가하고, gradle reload를 실행한다.

subprojects {
	dependencies {
		implementation 'com.github.ulsebocchio:jasypt-spring-boot-starter:3.0.5'
	}
}

 

Config 생성

@Configuration
@EnableEncrypableProperties
@ComponentScan("com.hanafn.ocr")

public class JasyptConfig {
	private static final String ALGORITHM = "PBEWithMD5AndDES";
	private String encryptKey = "test";  // secretKey에 해당
	
	@Bean("jasyptStringEncryptor")
	public StringEncryptor stringEncryptor(){
		PooledPBEStringEncryptor encryptor = new 	PooledPBEStringEncryptor();
		SimpleStringPBEConfig config = new SimpleStringPBEConfig();
		
		encryptor.setPassword(encrytKey);
		config.setAlgorithm(ALGORITHM);
		config.setKeyObtentionIterations("1000");
		config.setPoolSize("1");
		config.setSaltGeneratorClassName("org.jasypt.salt.RandomGenerator");
		config.setStringOutputType("base64");
		encryptor.setConfig(config);
		
		return encryptor;
	}
}

 

각 모듈 설정 파일 수정

jasypt:
	encryptor:
		bean: jasyptStringEncryptor

 

.env 파일 수정

다음과 같이 ENC() 로 감싼 암호화 텍스트로 패스워드 변수를 수정해준다.

db_password=ENC("암호화된 텍스트")
ex: ENC(xUtTur3ookt8ibe....)

 


로컬 테스트

패키지 설정

물론 스프링 애플리케이션에 암복호화를 하는 코드를 작성해서 테스트해봐도 되지만, 나는 그게 귀찮았다. 그래서 spring-boot-starter 패키지 외에도 별도로 일반 jasypt 패키지를 다운받아 윈도우 cmd 창에서 테스트를 진행했다. Github 레포지토리의 README에서 :Download distributable: jasypt 1.9.3 (binaries and javadocs)” 링크를 클릭해 다운받았다.

 

암복호화 로컬 테스트

다운받은 파일을 압축 해제하고, cmd 상에서 [압축 해제 경로]/bin으로 이동한 뒤 아래 명령을 실행하면 된다. 암호화 시 나오는 output은 실행할 때마다 달라지는 것이 정상이다. 여기서 입력되는 “password”값이 JasyptConfig의 “encryptKey” 값과 동일해야 한다.

# 암호화 테스트
encrypt.bat input="[암호화할 텍스트]" password="test" algorithm="PBEWithMD5AndDES"

# 복호화 테스트
decrypt.bat input="[암호화결과 output]" password="test" algorithm="PBEWithMD5AndDES"

 


테스트

컨테이너 실행

내 경우 mariaDB 컨테이너가 우선적으로 실행된 뒤 나머지 서버(config, discovery 등)이 실행되도록 되어있다. Jasypt는 자바 코드 기반으로 동작하는데, 가장 우선적으로 올라가야 할 mariaDB는 openJDK가 설치되어 있지 않기 때문에 해당 암복호화 기능을 사용할 수는 없다.

상사에게 문의해본 결과, 해당 부분이 문제가 되는 이유는 초기 솔루션 설치 시점이 아니라 운영 도중이라고 하며, 즉 처음에 컨테이너가 올라갈 때에는 .env 파일에 패스워드 평문을 쓰는 것은 아무런 상관이 없다는 답변을 받았다. 따라서 솔루션 설치 시에는 평문을 사용하여 DB만 컨테이너 이미지를 생성하고, 나머지는 암호화된 텍스트를 넣어 실행시키면 된다.

# 평문이 저장된 .env 파일 사용
docker compose up -d mariadb_test
# 암호화된 텍스트가 저장된 .env 파일 사용
docker compose up -d --no-recreate

그래서 우선 DB 컨테이너만 명시해서 docker-compose up을 해준 뒤, 패스워드값을 변경하고 나머지 컨테이너를 생성해줬다. 이때, --no-recreate 옵션이 있어야 이전에 생성한 DB 컨테이너가 영향을 받지 않는다.

 

컨테이너 변수 확인

로그를 확인해보니 서버가 모두 실행되긴 했는데.. 정말 패스워드값이 서로 다르게 적용된 게 맞은걸까? 이를 확인하기 위해 docker inspect로 컨테이너에 적용된 환경변수 값을 조회해봤다. grep 시에는 “Env” 를 정확히 입력해야 한다. (대소문자를 구분하기 때문) DB 컨테이너와 일반 컨테이너 조회 결과 아래와 같이 출력되어, 정상적으로 적용되었음을 확인할 수 있었다.

docker inspect [컨테이너명] | grep "Env" -A 20

## DB 컨테이너 조회 결과 ## 
"Env": {
	"MYSQL_PASSWORD=[패스워드 평문]"
}

## 일반 컨테이너 조회 결과 ##
"Env": {
	"db.password=ENC([암호화된 텍스트])"
}

 


References

'Backend > spring' 카테고리의 다른 글

Spring Cloud란?(Eureka, zuul)  (0) 2025.03.27

배경

회사 폐쇄망에서 virtual box로 개발 환경을 설정해야 하는 일이 있었는데, rocky 8.4 OS 이미지만 주어진 상태였다. 그래서 docker 설치를 위해 패키지 rpm 파일을 반입해야 했다. 집에 있는 인터넷망에서 완전히 동일한 환경(virtual box)를 준비하고 그에 맞는 파일들을 다운받기로 했다. 

 

온라인 환경 설정

Virtual box 생성

우선 rocky OS 부터 다운받는다. 공식 사이트에서 "아카이브된 릴리즈 버전"을 선택하고, 원하는 환경에 맞는 폴더를 선택한다. 내 경우 https://dl.rockylinux.org/vault/rocky/8.4/Minimal/x86_64/iso/ 경로의 Rocky-8.4-x86_64-minimal.iso 파일을 받았다. 사실 나도 정확히 뭔지 모르고 일단 다운부터 받아봤는데, 다행히 잘 진행됐다. 

 

virtual box를 설치한 후 새로 만들기 버튼을 통해 위에서 받은 ISO 이미지를 선택해주면 된다. 

 

이제 해당 머신이 사용할 네트워크 설정이 필요한데, 네트워크 설정은 머신이 종료된 상태에서만 변경이 가능하다. 나는 NAT 네트워크로 설정해 주었다. 

 

참고로, NAT 네트워크 사용 시 네트워크 관리자 창에서 포트포워딩 등의 설정도 가능하다. 나는 인터넷망은 아니고, 회사의 폐쇄망에서 SSH 접속을 위해 게스트 IP와 port(22)를 입력하여 putty로 세션을 저장하여 사용했다. 

 

네트워크 설정

기본적인 설정이 완료한 후 머신을 시작하면 계정 생성 등의 절차를 진행한 뒤 터미널에 접속할 수 있게 된다. 이제 이 터미널에서 도커 설치에 필요한 파일들을 받기 위한 명령어를 실행하면 된다. 그런데 나는 호스트가 인터넷에 연결되어 있기 때문에 머신 내에서도 자연스럽게 사용할 수 있을 줄 알았는데, 내 경우에는 별도 설정이 필요했다, 

sudo nmcli connection show
sudo nmcli connection up enp0s3
ping 8.8.8.8 -c 4  # 정상 연결 테스트

 

nmcli를 통해 현재 커넥션을 조회해보니 enp0s3이 내려가 있어서, 연결 설정을 해준 뒤 ping을 통해 정상적으로 인터넷이 동작하는지 확인해줬다. 

 

폴더 마운트 설정

머신 내에서 도커 파일을 받고 나면 이를 외부(호스트)로 반출할 방법이 필요한데, 나는 호스트의 경로를 마운트하여 빼내기로 했다. USB를 연결하는 방법도 있는데, 왜인지 나는 계속 USB 인식이 안돼서 이 방법을 택했다. 우선 사진과 같이 마운트를 원하는 경로를 지정한다. 나는 호스트의 workspace/VM/share라는 폴더와, 머신 내부의 /home/share라는 폴더가 마운트되도록 설정했다. 

 

아래 명령어로 필수 패키지를 설치한 후, 메뉴 탭의 장치 > Guest Additions CD 이미지 삽입(게스트 확장 CD 이미지 삽입)을 선택한다. 

sudo dnf install -y epel release
sudo dnf groupinstall -y Development Tools"
sudo dnf install -y kernel-devel kernel-headers dkms gcc make perl bzip2

 

 

CD 이미지가 정상적으로 삽입이 됐다면 다음 명령어로 마운트 경로를 설정한다.  

sudo mount /dev/cdrom /mnt
cd /mnt
sudo ./VBoxLinuxAdditions.run
sudo reboot
lsmod | grep vboxguest

sudo mkdir -p /home/share
sudo mount -t vboxsf share
ls /home/share  # 마운트된 호스트 경로의 파일들이 보임

 

만약 패키지 버전과 OS 버전이 "정확하게" 일치하지 않는다면 위 과정에서 에러가 발생할 수 있다. 이 경우 다음 명령어를 실행한 후 위 작업을 다시 시도한다. 정상적으로 마운트가 완료되었다면, 호스트의 파일을 머신에서 볼 수 있고 머신의 파일을 호스트에서 볼 수 있게 된다. 

sudo dnf install -y kernel-devel-$(uanme -r) kernel-headers-$(uname -r)

docker 다운로드

rpm 파일 다운로드

처음에는 docker 엔진 설치 문서를 참고했는데, 이렇게 진행할 경우 5~8개? 정도의 패키지에 대한 설치 파일만 저장된다. 그런데 내 경우에는 회사에서 사용 중인 OS 이미지가 정말 필수 패키지만 존재하는 상태였기 때문에, 그에 따른 의존성 패키지들도 모두 다운로드할 필요가 있었다. 그래서 repotrack 명령어를 통해 rpm 파일들을 다운받았고, 약 190여 개의 파일들이 저장되었다. 

docker dnf install yum-utils-y
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
repotrack docker-ce docker-ce-cli containerd.io docker-compose-plugin

 

rpm 설치 테스트

회사에 반입하여 테스트하기 전에, 해당 파일들로 docker가 제대로 설치되는지 사전 테스트를 진행해보았다. 우선 rpm 파일은 서로 의존성을 갖고 있어서, 우선적으로 설치되어야 하는 패키지나 버전이 존재한다. 하지만 내가 받은 파일은 모두 190여개에 달했고, 이 파일들의 관계를 모두 파악하기란 현실적으로 불가능하다. 어차피 인터넷망을 통해 필요한 모든 파일들을 받은 것이고, 버전도 그에 맞게 레포지토리에서 가져온 것이므로 문제가 없을 것이라 기대하고 무작정 설치를 진행했다. 

 

우선 그 전에, 최대한 폐쇄망과 동일한 환경을 구성하기 위해 (혹시 몰라) 처음에 설정했던 네트워크 설정을 다시 꺼줬다. 

sudo nmcli connection show
sudo nmcli connection down enp0s3
ping 8.8.8.8 -c 4  # 안되는 것 확인

 

이후 rpm 파일을 모두 설치하는 쉘 파일을 작성했다. 

  • --force: 기존에 설치된 패키지여도 강제로 설치
  • --nodeps: 의존성 무시하고 설치
  • -U: i면 install, u면 update
#!bin/bash

cd "test/docker/rpms" || exit 1

for rpm in *.rpm; do
	rpm -Uvh --nosignature --force --nodeps "$rpm"
done


설치가 완료되면 도커가 정상적으로 실행되는지 확인한다. 

docker -v  # docker-ce-cli 정상 설치 시 표시됨
systemctl start docker  # 이걸 실행해야 엔진이 실행됨
systemctl status docker  # docker-ce, 도커 엔진 정상 설치 시 표시됨
docker ps

 

그런데 사실, 집에서 해봤을 때는 문제가 없었는데, 회사에서 동일한 파일로 테스트했을 때에는 rpm 설치 도중 core dump 에러가 발생했다. 정확히 에러가 발생하는 패키지 대상을 확인했고, rpm 관련 3개 파일에서 문제가 생기는 것을 발견했다. (rpm, rpm-libs, rpm-plugin-selinux) 버전만 조금 상이할 뿐 이미 설치되어 있는 패키지였기 때문에 이 3개를 제외하고 설치를 진행했고, 이후 docker rootless 모드 설정까지 문제없이 모두 진행되어 큰 문제는 없어보였다. 

프린터 인쇄 시스템

LPRng(Line Printer next gegeration)

  • 리눅스 초기에 많이 사용됨
  • 라인 프린터 데몬 프로토콜을 이용해서 프린터 스풀링과 네트워크 프린터 서버를 지원
  • 설정 파일: /etc/printcap

 

CUPS(Common Unix Printing System)

  • 애플이 개발한 오픈 소스 프린팅 시스템
  • HTTP 기반 IPP(Internet Printing Procotol) → 인터넷을 통해 프린터를 지원
  • 사용자 및 호스트 기반의 인증 제공
  • 데몬 이름: cupsd
  • 설정 파일 디렉터리: /etc/cups

 

 

프린터 설정

  • 로컬 접속과 네트워크 프린터 설정 2가지 방법 존재
  • 네트워크 프린터 설정 방법

 


사운드 카드 시스템

OSS(Open Sound System)

  • 리눅스 및 유닉스 계열에서 사운드를 만들고 캡쳐하는 인터페이스
  • 표준 유닉스 장치 시스템 콜(POSIX read, write, ioctl 등) 기반
  • 현재는 OSS보다 ALSA로 대체

 

ALSA(Advanced Linux Sound Architecture)

  • 사운드 장치 드라이버 제공을 위한 리눅스 커널 요소
  • 사운드 카드를 자동으로 구성하고, 다수의 장치를 관리하는 것이 목적
  • OSS를 기반으로 하여 하드웨어 기반 미디어 합성, 다중 채널 하드웨어 믹싱, 전이중 통신 등의 기능 제공
  • 환경 설정 파일: /etc/asound.state

 

SANE(Scanner Access Now Easy)

  • 스캐너, 비디오 캠 등 이미지 관련 하드웨어를 제어하는 API
  • 멀티 OS 지원
  • SCSI 스캐너: /dev/sg0, /dev/scanner
  • USB 스캐너: /dev/usb/scanner, /dev/usbscanner

 

XSANE(X based Interface for the SANE)

  • SANE 스캐너 기반의 X-윈도우 기반 스캔/이미지 수정 프로그램
  • 스캔 작업 뿐 아니라 캡쳐한 이미지 수정 작업도 가능
  • gpl 라이센스, 멀티 OS 지원

 


장치 활용 명령어

프린트 명령어

  • lpr <옵션> [파일명]: 프린터 작업 요청

  • lpq <옵션>: 프린터 큐의 작업 목록 출력

  • lprm <옵션>: 큐에 대기 중인 작업 삭제

  • lpc: 라인 프린터 컨트롤 프로그램
    • 프린터 상태 확인
    • 큐 활성화/비활성화
    • 큐의 작업 순서 변경

 

System V 계열 프린트 명령어

  • lp <옵션> [파일명]: 프린터 작업 요청

  • cancal [ReqID]: 프린터 작업 취소
    • -a: 모든 작업 취소
  • lpstat <옵션>: 프린터 큐 상태 확인옵션 기능

 

사운드 카드 명령어

  • alsactl <옵션> [명령]: ALSA 사운드 카드 제어

 

  • alsamixer: ncurses 라이브러리 기반 오디오 프로그램
  • cdparanoia <옵션>: 오디오 CD 음악 추출

 

 

스캐너 관련 명령어

  • sane-find-scanner <옵션> [장치명]: SCSI 스캐너와 USB 스캐너 관련 장치 파일을 찾음

  • scanimage <옵션>: 이미지 스캔

  • scanadf <옵션>: 자동 문서 공급 장치가 장착된 스캐너에서 여러 개의 사진을 스캔

  • xcom: GUI 기반으로 평판 스캐너나 카메라로부터 이미지를 스캔

 


X-윈도우 개요

개념

  • 리눅스 환경의 각종 애플리케이션과 유틸리티에 대해 GUI를 제공
  • 플랫폼과 독립적으로 작동하는 그래픽 시스템
  • x-윈도우는 X11, X, X 윈도우 시스템이라고도 부름
  • 오픈 데스크톱 환경: KDE, GNOME, XFCE

 

특징

  • 네트워크 기반의 그래픽 환경을 지원
  • 이기종 시스템 사이에서도 사용 가능
  • 스크롤바, 아이콘, 색상 등 그래픽 환경 자원들이 통일되어 있지 않음
  • 디스플레이 장치에 의존적이지 않으며 원하는 인터페이스 설정 가능

 

네트워크 기반 클라이언트/서버 시스템

  • 서버: 클라이언트의 디스플레이 접근 제어, 클라이언트 간 자원 공유, 메세지 전달, 클라이언트와 입출력 장치의 중계
  • 클라이언트: 어플리케이션을 이용하여 X 서버의 기능 이용

 

구성요소의 종류

- windows manager: 창 크기나 색상 조절 등 GUI 관련 처리 담당
- display server ↔ client libraries: 통신 데이터는 display server protocol로 제어
- client libraries는 다양한 toolkit을 활용해서 작업을 처리함

 

  • Xfree86
    • display 서버를 지원해주는 라이브러리/프로토콜의 일종
    • X86 계열의 X서버 프로그램. 무료
  • XF86Config
    • XFree86 설정 파일 담당
    • 폰트, 키보드, 마우스, 비디오 카드 등의 색상 정보를 설정 가능
  • Xlib
    • 저수준 클라이언트 라이브러리
    • 윈도우 생성, 이벤트 처리, 창 조회, 키보드 처리 등의 기능 제공
  • XCB: Xlib보다 향상된 쓰레드, 확장성 제공
  • X 프로토콜: Xlib, Xtoolkit 인터페이스 사용
  • Xtoolkit: 고급 레벨의 GUI 생성 가능, Widget과 Intrinsic 지원

 

X-윈도우의 설정과 실행

  1. 윈도우 설정
    • init 프로세스 시 /etc/inittab 파일을 읽어 리눅스 환경 환경을 초기화함
    • 파일 시스템 점검, 서비스 프로세스 관리, 가상 콘솔 관리, 런 레벨 관리
  2. 윈도우 실행(startx -- [인자값])
    • 터미널 윈도우로 로그인하고 그래픽 환경으로 전환하고자 하는 경우 실행
    • 인자값 입력 시 여러 개의 x윈도우 프로그램 구동 가능
    • startx는 x윈도우를 실행하는 스크립트로, 시스템 환경을 초기화하고 xinit을 호출함
  3. DISPLAY 환경 변수
    • X 윈도우의 display 위치 지정
    • export DISPLAY=[IP]:[DISPLAY 번호],[스크린번호]

 


X-윈도우 매니저

x 윈도우 운영 시에는 다양한 관리자 프로그램들이 필요하다. 일반적으로 윈도우 매니저, 데스크톱 매니저, 디스플레이 매니저로 구분된다. 가장 핵심은 데스크톱 매니저이며, 데스크톱 매니저를 기반으로 윈도우와 디스플레이 매니저가 활성화되어 사용된다.

 

윈도우 매니저

  • 창의 배치와 표현을 담당하는 프로그램
  • XLib와 XCB 라이브러리를 사용
  • 리눅스에서 사용 가능한 윈도우 매니저는 다양함
  • 대표적인 윈도우 매니저
    • Enlinghtment: GNOME의 기본 윈도우 매니저
    • kwm: KDE v1.x의 기본 윈도우 매니저
    • etc: fvwm, twm, mw, windowmaker, AfterStep

 

데스크톱 매니저

  • Desktop Manager 또는 Desktop Environment
  • GUI 사용자에게 제공하는 인터페이스 스타일
  • 윈도우 매니저, 파일 관리자, 도움말, 제어판 등 다양한 도구를 제공하는 패키지 형태의 프로그램
  • 드래그 앤 드롭으로 프로세스 간의 통보 기능 지원
  • 대표적인 데스크톱 환경
    • KDE(Kool Desktop Environment): QT 툴 기반(그래픽 라이브러리), FreeBSD
    • GNOME(GNU Network Object Model Environment): QTK+이용, BSD 등에 포함
    • LXDE: Raspbian, GTK2 사용, 가벼운 모델
    • XFCE: GTK+2 사용, Xfwm 윈도우 매니저, 가벼운 모델

 

디스플레이 매니저

  • X-윈도우 상에서 작동하는 프로그램
  • X서버 접속 및 사용자 로그인 시 세션을 시작하기까지의 과정을 담당
  • 대표적인 디스플레이 매니저
    • kdm: KDE의 디스플레이 매니저
    • gdm: GNOME의 디스플레이 매니저. GTK, GNU GPK
    • etc: xdm, dtlogin

 


X-윈도우 활용 명령어

xhost

  • X 서버에 접속할 수 있는 클라이언트 지정 혹은 해제
  • 서버로의 요청 허용 여부를 호스트 단위로 제어
  • xhost [+|-] [IP|도메인명]
xhost +  # 모든 클라이언트 접속 허용
xhost + [IP]  # 해당 IP로부터 접속 허용

 

xauth

  • MMC 방식의 인증을 사용하기 위한 유틸리티
  • x윈도우 실행 시 생성되는 키를 기반으로 인증을 진행함
  • 쿠키 값으로 인증을 진행하기 때문에 xhost보다 더 강화됐다고 볼 수 있음
  • .Xauthority 파일에 해당 쿠키(magic cookie) 내용을 추가, 삭제, 리스트를 출력함
  • 당연히 $HOME/.Xauthority 파일에 대한 읽기/쓰기 권한 필요
  • xauth <옵션>
    • list: 모든 쿠키값 리스트 조회

 

X-윈도우 프로그램

 

 


References

+ Recent posts