본문 바로가기

카테고리 없음

[SeSAC 성동캠퍼스 1기] 네트워크 & 리눅스 기본 기술

1. 소개

 VMware & 우분투를 이용하여 네트워크 & 리눅스 기본 기능에 대한 강의를 받았다. 강의 자료를 미리 받은 것이 아니라 리눅스를 배우기 시작한 날에 받아서 리눅스의 어떤 부분을 배우는지는 당일에 알았다.

2. 리눅스

 리눅스 실습을 위해 VMware설치와 우분투 운영체제의 이미지파일 다운로드에 시간이 많이 소요되었다. VMware를 처음 사용한 것은 아니지만, 버전이 업그레이드되면서 예전에 익혔던 설치방법과는 다소 상이했다.

 

 VMware 설치 방법과 특정 운영체제의 이미지파일을 이용하여 가상머신을 구성하는 방식을 설명하려 했으나, 교육과정의 중점은 해당 내용이 아니므로 간단하게 설명하겠다.

 2 - 1. 가상머신 설정

 가상머신을 구성할 때, allocate all disk space now 옵션이 있다. 해당 옵션을 선택하면 설정한 디스크 용량을 가상머신에 바로 할당해 주기 때문에 속도가 빨라지는 장점이 있다. 하지만 백업 시에는 설정한 디스크 용량이 지정되어 있으므로 큰 용량 때문에 백업 시간이 오래 걸릴 수 있다. 운영체제의 요구 스펙이 생각보다 높아서 처음 가상 RAM은 최소 4GB 이상을 권장한다. 가상머신을 구성했다면, CLI 환경으로 바꾼 후에 다시 가상 RAM의 크기를 줄이면 된다.

 

 VMware에 가상머신을 구성했다면, 앞으로는 주로 SSH 클라이언트로만 접속하기때문에 (GUI 환경이라면) CLI 환경으로 바꿔준다. 리눅스에서는 부팅 레벨을 변경하면 되는데, 강의에서는 sudo systemctl set-default multi-user.target 명령어를 사용한다. 해당 명령을 사용하면 리눅스의 부팅 레벨을 3으로 바꿔준다. 리눅스의 부팅 레벨 3은 NFS를 허용하는 멀티유저 실행 모드인데, NFS는 Network File System 프로토콜을 의미한다. NFS는 네트워크로 연결된 컴퓨터의 파일 시스템에 연결할 수 있도록 해 준다. 그 후에 리눅스에 openssh-server 패키지를 설치해준다. 여기까지 구성했다면 앞으로는 가상머신의 전원만 켜 두고, SSH 클라이언트를 이용하여 해당 가상머신에 접속하면 된다.

 2 - 2. 리눅스 파일시스템 

 리눅스의 파일 시스템은 다음과 같다. 그중에서 교육과 필요한 부분만 알아보겠다.

 /bin: 바이너리 파일들이 모여있으며, 일부 바이너리 파일은 /usr/bin의 심볼릭 링크이다. /usr/bin과의 차이점은 /bin에는 추가로 시스템관리자를 위한 명령어도 존재한다.

 /boot: 부팅 프로세스에 대한 파일이 존재한다.

 /dev: device 관련 파일이 존재한다.

 /etc: 시스템의 구성 파일이 존재한다.

 /home: 사용자의 홈 디렉토리를 포함하고 있다.

 /lib: 라이브러리 파일들이 존재한다.

 /opt: 설치된 소프트웨어가 존재한다.

 /proc: 프로세스에 대한 정보가 파일로 존재한다.

 /sbin: system + binary의 줄임말이며, 시스템과 관련된 바이너리 파일들이 존재한다.

 /usr: 대체로 사용자 프로그램들이 존재한다.

 /var: log 파일과 그 외의 파일들이 존재한다.

 2 - 3. vi 편집기 (+미션1)

 vi 편집기는 리눅스에 기본적으로 내장된 편집기이다. 사용하는데 많이 불편하지만, 인터넷이 연결되지 않아 외부 네트워크 연결이 불가능하면서 추가적인 편집기를 사용할 수 없는 경우에 사용된다.

 

 vi 편집기에는 3가지 모드가 있다.

  1. 명령 모드: 처음 vi를 실행하면 지정되는 모드로 i,a,o를 누르면 입력 모드로 이동하며, :를 누르면 ex모드로 이동한다.

  2. 입력 모드: 편집기에서 문서를 작성하는 모드이다. esc키를 누르면 명령 모드로 돌아간다.

  3. ex 모드: 저장(w), 종료(q)를 실행하는 모드이다. esc키를 누르면 명령 모드로 돌아간다.

 

 처음에는 명령 모드에서 시작한다. 입력 모드에서 타이핑을 한 후에 명령모드를 거쳐 ex 모드로 이동하면 편집 내용을 저장하거나 종료할 수 있다.

 

 ex모드에서 :n(n = 숫자)를 입력하고 엔터를 누르면 해당 라인으로 이동한다.

 ex모드에서 :$를 입력하고 엔터를 누르면 마지막 줄로 이동한다.

 2 - 4. dpkg & apt-get

 dpkg는 윈도우 운영체제의 exe파일과 같은 역할을 한다. 하지만 실행을 위한 패키지만 설치할 뿐이며, 해당 패키지를 실행시키기 위한 다른 패키지는 추가로 설치하지 않는다. 이런 불편한 점을 해결하기 위해서 apt-get 방식이 도입되었고 apt-get을 이용하여 패키지를 설치하면, /etc/apt/sources.list 파일의 링크를 참조하여 추가로 필요한 dpkg를 같이 설치해 준다.

 2 - 5. tar

 tar은 Tape ARchiver의 줄임말로, 리눅스에서 여러 개의 파일을 하나의 파일로 만들거나 그 역순의 작업을 한다. tar 자체에는 데이터의 용량을 감소시키는 역할은 없으며, bzip2 압축을 위한 -j옵션을 사용하거나 gzip 압축을 위한 -z옵션을 사용하여 데이터의 용량을 감소시킬 수 있다. 주로 사용하는 옵션은 아래와 같다.

 

 -c : 여러 파일을 묶어서 새로운 아카이브 파일을 만든다.

 -x : 아카이브 파일 추출한다.

 -z : gzip으로 압축한다.

 -v : 처리 정보를 보여준다.

 -f : 아카이브를 지정한다.

 2 - 6. 하드링크 & 심볼릭 링크

 하드링크와 심볼릭링크를 알아보기전에 inode에 대해 간략히 알아보겠다. inode는 유닉스 파일 시스템에서 파일을 다루는 자료구조이다. 파일은 inode 번호를 가지고, inode는 파일 내용에 대한 주소값을 가르킨다.

 

 하드링크는 원본파일과 동일한 inode 번호를 가진다. 따라서 원본파일을 삭제하더라도 하드링크는 동일한 inode를 가지므로 파일 내용에 참조할 수 있다. 하지만 하드링크는 디렉토리를 링크하지 못한다.

 

 소프트링크는 원본파일과 다른 inode 번호를 가진다. 다른 inode는 원본파일을 가리키는 링크를 가리키는 방식이라 원본파일이 삭제되면 소프트링크는 원본파일에 참조할 수 없다.

하드링크 & 소프트링크와 inode

 2 - 7. chmod & chown

 chmod 명령어는 파일의 권한을 변경하고, chown 명령어는 파일의 소유권을 변경한다.

 

 chmod는 예시로 설명하겠다.

 -rw-rw-r-- test파일이 존재할 경우, 유저에게 실행(x)권한을 추가하고, 그룹에게 쓰기(w)권한을 제거하고, 모두에게 읽기(r)권한을 제거하고 실행(x)권한을 추가하고 싶을 때는 아래과 같이 2가지 방법이 있다.

 $ chmod u+x test; chmod g-w test; chmod o-r+x test;

 $ chmod 741 test 

 

 chown의 경우 ~/file파일을 1000그룹의 tester유저에게 소유권을 바꿔줄 경우에는, $ chown tester:1000 ~/file 명령을 사용하면 된다.

 2 - 8. nmtui

 nmtui는 리눅스의 네트워크 관리 도구이다. 관리 도구라서 vi같은 편집기로 작성하는 방식이 아니라 make menuconfig같은 방식이라고 생각하면 된다.

 2 - 9. 리눅스 실무 명령

 강사님께서 준비한 리눅스 실무 명령이라는 문제들을 내 주셨다. 문제들은 아래와 같다.

 

  1. /etc/ 디렉토리의 파일들을 시간순으로 출력한다.

    $ ls -altr /etc
  2. /var/log/syslog는 대부분의 시스템 로그를 기록한다. 터미널에 실시간 출력되도록 해 본다.

    $ tail -f /var/log/syslog
  3. 이전 명령어들을 확인해본다.

    $ history
  4. 파일 복사, 삭제, 옮기기

    $ cp file1 file2; rm file1; mv file2 ~/file2

  5. /etc 디렉토리의 파일들을 tar로 묶고, 풀어본다.

    $ sudo tar -cvf mytar.tar /etc; tar -xvf mytar.tar
  6. 파일을 압축하고 풀어본다.

    $ zip files.zip ./file; unzip files.zip
  7. tar와 압축을 동시에 수행해본다.

    $ sudo tar -czvf mytar.tar.gz /etc; tar -xzvf mytar.tar.gz
  8. 랜카드에 설정된 인터페이스와 IP를 확인해본다.

    $ ifconfig
  9. 윈도우의 작업관리자와 동일한, 현재 프로세스정보를 확인한다.

    $ ps
  10. 시스템 부팅 시 메시지들을 확인해본다.

    $ dmesg
  11. 다른 서버로 ssh 접속을 수행한다.

    $ ssh <ID>@<IP> 
  12. 다른 서버로부터 파일을 복사해온다, 복사해간다.

    $ scp <ID>@<IP>:<path> ./; scp file <ID>@<IP>:<path>
  13. 명령을 연속으로 수행한다.

    $ <command1>;<command2>;<command3>
  14. 1기가 파일을 생성한다.

    $ head -c 1G /dev/urandom > file
  15. http://www.naver.com 서버가 살아있는지 확인한다.

    $ ping www.naver.com
  16. 내 컴퓨터에서 http://www.naver.com 까지 지나가는 네트워크 경로를 확인한다.

    $ traceroute www.naver.com
  17. tcpdump라는 유틸을 설치한다.

    $ sudo apt-get install tcpdump
  18. tcpdump를 이용하여 웹포트를 스니핑한다.

    $ sudo tcpdump port 80 -w ./test.pcap
  19. tcpdump로 덤프한 파일을 윈도우상에서 분석한다.

    > scp [리눅스 ID]@[리눅스 IP]:[덤프한 파일 위치] [윈도우에 받을 위치]
  20. 현재 내가 관리하는 서버에 열려있는 포트와 열고있는 프로세스를 확인한다.

    $ netstat -anp
  21. httpd 서비스를 시작/중지 한다.

    $ systemctl start httpd; systemctl stop httpd;
  22. named.conf 파일이 어디에 있는지 찾아본다.

    $ sudo find / -name 'named.conf'
  23. 현재 시간을 확인한다.

    $ date
  24. 설치된 서버의 시간이 맞지않는다. 시간 동기화를 시킨다.

    $ sudo apt-get install rdate; rdate -s time.bora.net && hwclock -w
  25. 현재 모든 프로세스를 출력해본다.

    $ ps -ef
  26. 특정 프로세스를 죽인다.

    $ kill -9 [프로세스ID]
  27. 화면을 지운다.

    $ clear
  28. vi로 두 개의 파일을 비교한다.

    $ vi -d file1 file2
  29. 프로세스를 트레이스해 본다.

    $ sudo strace -p [프로세스ID]
  30. cron 사용법: 2 - 12. cron 참조

 2 - 10. 미션2

 강의 도중에 강사님께서 미션을 주셨는데 내용은 아래와 같다.

 

  1. 사용자 user1~user5 5명의 계정을 추가하라.

  2. 모든 사용자의 패스워드는 12345로 만들어주자.

  3. /etc/passwd 파일을 내 디렉토리에 passwd.backup 파일로 복사해주자.

  4. 복사한 passwd.backup 파일은 아무도 읽을 수 없도록 소유권을 변경해주자.

  5. 내 홈 디렉토리에 sysBackup이라는 디렉토리를 생성하고, passwd.backup파일을 이 디렉토리 안으로 옮겨 주자.

  6. 이 사용자 중, user3은 로그인할 수 없도록 쉘을 바꿔주자.

 

 각 번호마다 특정명령어나 vi편집기를 이용하여 특정 파일의 내용을 변경하면 되는 작업이었다. 해결 방법은 아래와 같다.

 

 1. adduser user1; adduser user2; adduser user3; adduser user4;  adduser user5;

 2. passwd user1; passwd user2; passwd user3; passwd user4;  passwd user5;

 3. cp /etc/passwd ~/passwd.backup

 4. chmod 000 ~/passwd.backup

 5. mkdir ~/sysBackup; mv ~/passwd.backup ~/sysBackup

 6. (관리자 계정이 아니라면 앞에 sudo) vi /etc/passwd 입력 후에, vi편집기의 user3이 적힌 라인에서 "/bin/bash" 부분을 "/usr/sbin/nologin"으로 바꿔준다.

 2 - 11. 미션3: 웹서버 열기

 그림 파일 하나를 준비하고 nginx의 웹 서버를 구동하여, 웹 서버의 메인 화면이 준비한 그림 파일로 설정하는 웹 서버를 만드는 미션이었다. 아래는 미션을 진행하기 위한 과정을 설명했다.

준비한 그림

 1. 내가 준비한 그림은 위의 그림이고, 윈도우의 scp 명령어를 사용하여 리눅스 서버에 전달하였다.

  (cmd)> scp [그림 파일 위치(그림파일을 cmd에 드래그해도 된다.)] tester@192.168.254.130:~

    그림 파일의 링크를 알고있으면 리눅스 서버에서 wget 명령어를 사용해도 된다.

 

 2. 리눅스에서 apt-get으로 nginx를 설치하고, nginx의 홈 디렉토리인 /var/www/html에 준비한 그림을 mv명령어로 옮겨주었다.

  (sh)$ sudo apt-get install nginx -y; mv ~/SK.jpg /var/www/html/

 

 3. /var/www/html 내부에 index.html파일을 생성하고 아래와 같이 html파일을 작성한다.

<img src="./SK.jpg">

 

 4. 리눅스 서버와 같은 네트워크에서 웹 브라우저에 리눅스 서버의 주소를 입력하면, 아래와 같이 접속되는 것을 확인할 수 있다.

리눅스 웹 서버 접속

 예전에는 Apache를 사용했었던 기억이 났다.

 2 - 12. cron

 cron은 특정 명령을 주기적으로 실행할 수 있는 리눅스 운영체제의 명령어이다.

 /etc/crontab파일에 원하는 명령을 추가하면, cron 프로세스가 /etc/crontab파일의 명령어를 지정한 주기로 실행한다.

 crontab 파일에는 아래와 같은 형식으로 작성한다.

 

 (분) (시) (일) (달) (주간) (사용자) (명령어)

 

 사용자 부분은 관리자권한을 요구할 수 있는 명령이 실행될 수 있으니 root를 사용한다. 시간과 관련된 부분은 주석으로 설명되어있지만, 예시를 추가하면 다음과 같다.

 

 5 * * * * (사용자) (명령어) = 매 시각 5분에 사용자가 명령어를 수행한다.

 10 23 * * * (사용자) (명령어) = 매일 23시 10분에 사용자가 명령어를 수행한다.

 20 13 * * 5 (사용자) (명령어) = 금요일 13시 20분일 때마다 사용자가 명령어를 수행한다.

 */20 * * 3 * (사용자) (명령어) = 3월에는 20분마다 사용자가 명령어를 수행한다.

 

 추가로 /etc/cron.d/anacron이라는 파일이 있다. 해당 파일은 정해진 시간 내에 명령어가 수행했는지 확인하고 명령어가 수행되지 않았다면, 해당 작업을 여유있게 실행한다. 

 2 - 13. 미션4

 미션4는 cron으로 5분마다 /etc 디렉토리를 현재 디렉토리 아래에 시간 이름으로 백업하는 미션이다. 강사님께서는 백업을 위한 shell 파일을 따로 주셨다. 따라서 5분마다 강사님께서 주신 쉘파일을 실행하면 되는 미션이다. 강사님이 주신 backup.sh파일은 아래와 같다.

#!/bin/bash
today=$(date +%Y%m%d_%H-%M-%S)
tar czf /home/tester/etc-$today.tar.gz /etc

 

  나의 경우는 아래와 같이 해결했다.

 $ cd ~; mkdir backup; mv ~/backup.sh ~/backup/backup.sh; sudo vi /etc/crontab

  /etc/crontab 파일에 아래의 줄 추가

 */5 * * * * root /home/tester/backup/backup.sh

 

 위와 같이 변경하면 5분마다 /etc폴더를 etc-(현재 시각).tar.gz 파일로 만들어서 ~/backup 폴더에 저장할 것이다. 

 2 - 14. 미션5

 미션5는 nginx 서버와 관련된 내용이다. 내용은 아래와 같다.

 

  1. nginx의 서비스 포트를 9999번으로 변경한 후, 서버를 재구동, 브라우저에서 접속을 확인하시오.

  2. 변경된 포트 번호로 리슨하고있는 상태를 확인하시오.

 

 나의 해결 방법은 아래와 같다.

 

  $ sudo vi /etc/nginx/sites-enabled/default 명령어를 통해 server { } 내부의 listen 80부분을 listen 9999로 바꿔준다. 참고로 listen [::]:80은 IPv6인데, IPv4로 접속하므로 해당 부분은 변경하지 않아도 된다.

 그 후에는 $ sudo systemctl restart nginx 명령어를 통해 nginx서버를 재구동한다.

 브라우저에서 접속할 때는 <리눅스 IP주소>:9999를 입력하여 접속을 확인한다.

 변경된 포트 번호로 리슨하고 있는지는 $ netstat -anp | grep :9999 명령어로 확인할 수 있다.

IP 변경 후에 포트를 변경한 것이라 포트 번호만 보면 된다.

 2 - 15. netstat & arp & nslookup & dig

 netstat는 네트워크 관련 정보를 확인하는데 사용하는 명령어이다.

 netstat -anp | grep :[포트 번호] 같이 특정 포트의 상태를 확인할 수 있다.

 

 arp는 연결하려는 시스템의 mac주소를 확인할 때 사용한다.

 주로 arp -a형식으로 사용한다.

 

 nslookup은 DNS에 질의하여, 도메인의 정보를 조회하는 명령어이다.

 $ nslookup [도메인 이름] 을 사용하면, 도메인 이름에 해당하는 ip주소를 알아낼 수 있다. 

 

 dig은 nslookup과 같이 DNS를 질의할 수 있지만, nslookup보다 편한 인터페이스를 제공한다.

2 - 16. 기타 명령어

 $ cat [파일 이름] = 파일의 내용을 출력한다.

   ($ cat > [파일 이름] 명령을 사용하고  [내용] 입력 후 ctrl + d = 내용 오버라이딩)

   ($ cat >> [파일 이름] 명령을 사용하고  [내용] 입력 후 ctrl + d = 내용 추가)

   (윈도우에서는 cmd에서 > copy con [파일 이름] 명령을 사용하고 [내용] 입력 후 ctrl + z = 내용 오버라이딩)

 

 $ watch -n [x초] [명령어] = x초마다 명령어 실행

 

 $ grep [문자열] -r [위치] = 특정 위치의 하위 파일까지 문자열 검사

   (나는 주로 -inr 옵셥을 사용한다 = 대소문자 무시[i], 줄번호 출력[n], 하위 디럭토리도 탐색[r])

 

 $ export = 리눅스에서 설정된 변수의 값을 확인할 때 사용한다.

   (윈도우의 환경변수에 해당하는 값은 $PATH로, 리눅스 터미널에 $PATH를 입력하면 환경변수의 값을 확인할 수 있다.)

 

 $ witch [명령어] = 명령어의 바이너리 파일의 위치을 알려준다.

   (/usr/bin/sudo 대신에 해킹용 sudo 파일을 만들어서 해킹용 sudo 파일로 비밀번호를 유도하는 해킹 방식도 있다.)

 

 $ uname -a = 나의 시스템 정보를 출력

 

 $ nohup [명령] = 세션이 끝나도 지정한 명령을 실행하는 명령어

2 - 17. 3-Tier 환경 구성

 강사님을 통해 3-Tier 환경을 구성해보았다. 일단 3-Tier 환경은 아래와 같다.

Web - Was - DB의 3 - Tier 환경

 3-Tier의 구조는 위와 같이 구성되어있으며, 동작 단계는 아래와 같다.

 

   1. 사용자가 80번 포트(HTTP프로토콜)을 통해 Web에 요청한다.

   2. Web에서 자체적으로 처리하지 못하는 요청이라면 WAS에 요청한다. (Tomcat의 경우 8080번 포트 사용)

   3. WAS에서 DB로 데이터쿼리를 요청한다.

   4. DB에서 요청에 대한 결과를 반환한다.

   5. WAS에서 Web으로 결과를 반환한다.

   6. Web에서 사용자에게 응답한다.

 

 Web, WAS, DB는 각각 vmware에서 하나의 가상머신이 되고 NAT모드로 네트워크 연결했다. 추가로 Attacker라는 가상머신을 생성하여 Web에 공격을 시도해 보았다.

 

  # case1: Attacker 가상머신으로 Web 가상머신을 공격하는 시나리오

 

 1. Attacker 가상머신에 공격에 필요한 툴을 설치하고 웹서버 IP에 공격을 시도한다. (나의 웹서버 IP는 10.10.10.6이다.)

$ sudo apt-get instlal hping3 -y
$ sudo hping3 --icmp 10.10.10.6 --rand-source

 

 2. Web서버 가상머신에서는 nginx를 설치하고 들어오는 패킷 정보를 저장한다.

$ sudo tcpdump -w ./web.pcap
$ sudo mv web.pcap /var/www/html/

 

 /var/www/html에 이동한 web.pcap은 웹서버에서 10.10.10.6/web.pcap으로 다운받을 수 있다.

 

 tcpdump 명령어로 패킷들을 덤프할 수 있다. 덤프된 패킷들은 웹서버에서 다운받아 Wireshark툴로 해당 패킷을 분석할 수 있다.

 

Wireshark 툴로 web.pcap을 열었을 때의 화면이다.

 icmp 옵션으로 공격했기 때문에 icmp 프로토콜을 확인하면 공격자의 주소가 Attacker 주소인 10.10.10.7이 아니라 임의로 설정된 것을 확인할 수 있다.

 

  # case2: Web 가상머신의 nginx와 WAS 가상머신의 tomcat을 연동하는 시나리오

 WAS 가상머신에 tomcat을 구동하기 위해 아래와 같이 진행하였다. 참고로 나의 WAS 가상머신 주소는 10.10.10.4이다.

$ wget https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.4/bin/apache-tomcat-9.0.4.tar.gz
$ tar xvzf ./apache-tomcat-9.0.4.tar.gz
$ sudo mkdir /usr/local/tomcat
$ sudo mv ./apache-tomcat-9.0.4/* /usr/local/tomcat/
$ sudo apt-get install openjdk-8-jdk
$ /usr/local/tomcat/bin/startup.sh

 

 tomcat을 구동하기 위해서 jdk도 설치하였다. tomcat은 /usr/local/tomcat/bin에서 startup.sh파일과 shutdown.sh파일로 구동하거나 구동을 끌 수 있다.

 

 Web 가상머신에서는 $ sudo vim /etc/nginx/sites-available/default 명령을 통해 아래와 같이 파일을 편집한다.

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /var/www/html;
        index index.html index.htm test.jsp index.nginx-debian.html;
        server_name _;

        location / {
                # try_files $uri $uri/ =404; # 해당 부분을 주석처리해야 정상적인 tomcat의 화면을 볼 수 있다. 
                index index.html index.htm index.jsp;
                proxy_pass http://10.10.10.4:8080;
        }
}

 

 그 후에 $ sudo systemctl restart nginx 명령을 통해 nginx을 재시작한다. 그리고 Web 가상머신의 주소인 10.10.10.6을 웹 브라우저에 입력하면, WAS 가상머신의 tomcat과 연동된 것을 확인할 수 있다.

 

 추가로 WAS가상머신에서 /usr/local/tomcat/webapps/ 에 존재하는 ROOT 디렉토리를 ROOT.ori로 바꾸고 새로 빈 ROOT디렉토리를 만들어서 hello가 적힌 index.html파일을 생성하면 Web서버의 화면이 hello가 적힌 화면으로 바뀐다.

$ sudo mv /usr/local/tomcat/webapps/ROOT /usr/local/tomcat/webapps/ROOT.ori
$ sudo mkdir /usr/local/tomcat/webapps/ROOT
$ echo hello > /usr/local/tomcat/webapps/ROOT/index.html

tomcat의 새로운 시작화면

 

  # case3: Web 가상머신의 nginx, WAS 가상머신의 tomcat, DB 가상머신의 mariaDB를 연동한 시나리오.

 

 DB 가상머신에서 mariadb-server를 설치하고 활성화 해 준다. 그리고 설정 파일을 아래와 같이 편집한다.

DB$ sudo apt-get install mariadb-server
DB$ sudo systemctl enable mariadb
DB$ sudo vim /etc/mysql/mariadb.conf.d/50-server.cnf
DB$ # 편집에서 bind-address를 0.0.0.0으로 바꿔주고 저장하면 외부접속이 허가된다.
DB$ sudo systemctl restart mariadb
DB$ sudo mysql -u root

 

 DB 가상머신에서 아래와 같이 DB와 Table을 추가한다.

DB$ sudo mysql -u root
> CREATE database mycl;
> use mycl;
> CREATE table userInfo (
-> uid int,
-> uname varchar(20),
-> pass varchar(128),
-> profile varchar(200),
-> priority int);
> INSERT into userInfo (uid, uname, pass, profile, priority) VALUES (0, "admin", "1234", "관리자", 0);
> INSERT into userInfo (uid, uname, pass, profile, priority) VALUES (1, "user1", "abcd", "행인1", 1);
> INSERT into userInfo (uid, uname, pass, profile, priority) VALUES (2, "user2", "abcd", "행인2", 1);
> INSERT into userInfo (uid, uname, pass, profile, priority) VALUES (3, "user3", "abcd", "행인3", 1);
> SELECT * FROM userInfo;
> use mysql;
> CREATE user 'mydb'@'%' identified by 'abcd'; # '%'는 모든 IP에 대해 접속 허용
> GRANT all privileges on *.* to mydb@'%'; # *.*는 모든 데이터베이스의 모든 테이블을 의미
> FLUSH privileges; # 업데이트

 

 추가로 WAS 가상머신에서 아래와 같이 mariadb 클라이언트와 자바 라이브러리 파일을 받아서 필요한 위치에 복사한다. 그리고 /etc/profile 파일을 편집한다.

WAS$ sudo apt install mariadb-client-core-10.3 -y # mariaDB 클라이언트 설치
WAS$ mysql -u mydb -h 10.10.10.5 -p # mariaDB 원격 접속 -u는 userid, -h는 호스트 주소, -p는 비밀번호 간접 입력
WAS$ wget https://dlm.mariadb.com/1965742/Connectors/java/connector-java-2.7.5/mariadb-java-client-2.7.5.jar
WAS$ sudo cp mariadb-java-client-2.7.5.jar /usr/lib/jvm/java-1.8.0-openjdk-amd64/lib/
WAS$ sudo cp mariadb-java-client-2.7.5.jar /usr/local/tomcat/lib/
WAS$ wget https://downloads.mysql.com/archives/get/p/3/file/mysql-connector-java-5.1.40.tar.gz
WAS$ tar xvzf mysql-connector-java-5.1.40.tar.gz
WAS$ sudo cp mysql-connector-java-5.1.40/mysql-connector-java-5.1.40-bin.jar /usr/local/tomcat/lib/
WAS$ sudo vim /etc/profile

-----(아래의 내용을 맨 밑에 추가)-----
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-amd64/
export CATALINA_HOME=/usr/local/tomcat
PATH=$PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin
export CLASSPATH=.:$JAVA_HOME/lib/mariadb-java-client-2.7.5.jar:$CATALINA_HOME/lib/mariadb-java-client-2.7.5.jar
-----(내용 끝)-----

WAS$ source /etc/profile # /etc/profile 스크립트를 바로 적용한다.

 

 변경하였으면, WAS 가상머신에서 $ /usr/local/tomcat/bin/shutdown.sh 을 실행해서 tomcat을 꺼 준다.

 그리고 $ /usr/local/tomcat/bin/startup.sh 을 실행해서 tomcat을 켜 준다.

 

 WAS 가상머신에서 $ sudo vi /usr/local/tomcat/webapps/ROOT/login.jsp 명령을 입력하고 아래와 같이 작성한다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="java.sql.*" %>
<%@ page import="java.io.PrintWriter" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<%
String uid = request.getParameter("username");
String pwd = request.getParameter("password");
String DB_URL = "jdbc:mysql://10.10.10.5:3306/mycl";
String DB_USER = "mydb";
String DB_PASSWORD= "abcd";
String sel = "";
ResultSet rs = null;
Connection conn;
Statement stmt;

try {
        Class.forName("com.mysql.jdbc.Driver");
        conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
        stmt = conn.createStatement();
        //사용자 정보 조회
        sel = "select * from userInfo where uname='" + uid + "' and pass='" + pwd + "'";
        rs = stmt.executeQuery(sel);

        String fileName = "main.html";
        String filePath = application.getRealPath("./" + fileName);
        PrintWriter writer = new PrintWriter(filePath);
        if (rs.next()) {
                String main_html_contents = "<html><head><meta charset='utf-8'><title>로그인 성공</title></head><body><div>" +
                        uid + "님 반갑습니다.</div></body></html>";
                writer.println(main_html_contents);
                writer.close();
                Thread.sleep(500); // main.html이 생성되기 전에 연결되는 것을 방지
                response.sendRedirect("main.html");
                // out.println("<font color='blue'><h1>Success</h1></font>");
        }
        else {
                response.sendRedirect("login.html");
                // out.println("<font color='red'><h1>Login Fail</h1></font>");
        }
        conn.close();
} catch(Exception e) {
        out.println(e.getMessage());
}
%>

 

 해당 코드는 로그인에 성공하면, 누구인지 판별하여 "[user이름]님 반갑습니다"라는 메시지가 나오는 main.html 코드를 생성하고 main.html로 이동한다.

(실습용으로 위와 같이 작성하였지만, 실제 서비스 용도로 저런 코드를 사용하면 안 된다.)

 

 추가로 로그인 페이지를 만들기 위해 WAS 가상머신에서 $ sudo vi /usr/local/tomcat/webapps/ROOT/login.html 명령을 입력하고 아래와 같이 작성한다.

<html>
<head><meta charset="utf-8"></head>
        <body>
                <form method="POST" action="./login.jsp">
                        User ID : <input type="text" name="username" value = ""/> </br>
                        Password : <input type="password" name="password" value = ""/> <p>
                        <input type="submit" value="login">
                </form>
        </body>
</html>

그리고 다시 Web서버 주소인 10.10.10.6/login.html을 웹 브라우저에 입력하면 로그인 화면을 볼 수 있다.

 

보안을 위한 방법으로, User ID 부분 위에

<input type="hidden" name="session" value = "specialvalue"/> </br>

를 입력하고 Web서버에 다시 접속하면, 보면 아무것도 추가되지 않는 것처럼 보인다. 하지만 login.jsp파일에서 session의 value값을 읽어올 수 있다. 그렇게 되면, login.jsp파일에 지정된 session의 value값과 요청받은 session의 value이 다르거나 존재하지 않는다면 비정상적인 접근이라는 것을 파악할 수 있어서 해당 코드를 추가하면 보안에 도움이 된다고 한다.

 

 로그인에 성공하면 login.jsp가 생성해주는 main.html 페이지로 이동하고, 로그인에 실패하면 login.html 페이지로 다시 이동한다. 아래와 같이 로그인 성공 화면을 확인할 수 있다.

 # 취약점: SQL Injection

 위의 jsp파일의 쿼리문은 id와 password모두가 같은지에 대한 조건문이 참이면 로그인에 성공하는 방식이다. 그 취약점을 이용하여 id와 password를 둘 다 몰라도 로그인에 성공하는 방법이 있다. 바로 아래와 같이 로그인하는 방식이다.

DB에 a' or 'x'='x 값의 uname은 없지만, 로그인에 성공한다.

 Password 부분이 보이지 않지만, User ID부분과 동일하게 입력한다. where uname='" + uid + "' and pass='" + pwd + "'" 부분에서 uid와 pwd부분에 [a' or 'x'='x]를 대입하면, where uname='a' or 'x'='x' and pass='a' or 'x'='x' 이 된다. and의 양쪽 부분이 True가 되므로 결국 로그인에 성공하게 되는 방식이다. jsp의 쿼리문의 "또는 '에 따라 "대신 '를 작성해야 할 수 있다.

 

 해당 취약점을 예방하기 위해서는 입력값에 ', ", =같은 문자를 입력받으면 로그하지 못하도록 조치해야 할 것이다.

3. 네트워크

 3 - 1. IP주소 체계

 IP주소 체계를 이해하기 위해서는 IPv4가 32자리의 2진수로 구성되어있다는 것과 8자리씩 끊어서 표현하는 방식을 알아야한다. IP주소 체계를 쉽게 설명하면 네트워크 영역과와 호스트 영역을 나누는 방식이라고 생각하면 된다. IP주소 클래스는. A, B, C, D, E 총 5가지가 있는데 아래와 같이 분류한다.

IP주소의 5가지 체계

 이 중에서 클래스 D는 여러 컴퓨터에게 동시에 송출하기 위한 용도로 사용되고, 클래스 E는 예약되어있으므로 클래스 A, B, C 위주로 설명하겠다.

 

 클래스 A는 맨 앞의 비트가 0이며, 네트워크 비트가 8개, 호스트 비트가 24개로 설정된 방식이다. 클래스 A에서 할당 가능한 IP 주소의 범위는 0.0.0.0 ~ 126.255.255.255이며, 다른 클래스와 비교하면 가장 많은 IP주소를 할당할 수 있다. 127.255.255.255까지 범위라고 생각할 수 있는데, 127.x.x.x는 루프백 주소로 사용하기 위해 사용하지 않는다. 개인 IP범위는 10.0.0.0 ~ 10.255.255.255이다.

 앞의 8비트의 값이 0 ~ 126인 IP주소라면(10으로 시작하는 개인 IP 제외), 클래스 A로 판단할 수 있으므로 앞의 8비트가 네트워크 주소이며, 뒤의 24비트가 호스트 주소로 판단할 수 있다. 그리고 네트워크 주소와 브로드캐스트 주소를 고려해야 한다.

 예를 들어 3.0.0.0인 IP주소가 있으면, 클래스 A로 판단할 수 있으므로 앞의 8비트가 네트워크 주소이며, 뒤의 24비트가 호스트 주소로 판단할 수 있다. 호스트 주소 비트에 전부 0으로 설정된 3.0.0.0은 네트워크 주소로 사용하고 호스트 주소 비트에 전부 1로 설정된 3.255.255.255는 브로트캐스트 주소로 사용해야 한다. 따라서 A클래스로 3.0.0.0을 할당받으면 호스트에게 할당할 수 있는 IP개수는 (2^24)-2개가 된다.

 

 클래스 B는 첫 번째와 두 번째의 비트가 각각 1, 0이며, 네트워크 비트가 16개, 호스트 비트가 16개로 설정된 방식이다. 클래스 B에서 할당 가능한 IP주소의 범위는 128.0.0.0 ~ 191.255.255.255이다. 개인 IP범위는 172.16.0.0 ~ 172.31.255.255이다.

 앞의 8비트의 값이 128 ~ 191인 IP주소라면(172로 시작하는 일부 개인 IP 제외), 클래스 B로 판단할 수 있으므로 앞의 16비트가 네트워크 주소이며, 뒤의 16비트가 호스트 주소로 판단할 수 있다. 그리고 네트워크 주소와 브로드캐스트 주소를 고려해야 한다.

 예를 들어 130.0.0.0인 IP주소가 있으면, 클래스 A로 판단할 수 있으므로 앞의 16비트가 네트워크 주소이며, 뒤의 16비트가 호스트 주소로 판단할 수 있다. 호스트 주소 비트에 전부 0으로 설정된 130.0.0.0은 네트워크 주소로 사용하고 호스트 주소 비트에 전부 1로 설정된 130.0.255.255는 브로트캐스트 주소로 사용해야 한다. 따라서 B클래스로 130.0.0.0을 할당받으면 호스트에게 할당할 수 있는 IP개수는 (2^16)-2개가 된다.

 

 클래스 C는 첫 번째부터 세 번째까지의 비트가 각각 1, 1, 0이며, 네트워크 비트가 24개, 호스트 비트가 8개로 설정된 방식이다. 클래스 C에서 할당 가능한 IP주소의 범위는 192.0.0.0 ~ 223.255.255.255이다. 개인 IP범위는 192.168.0.0 ~ 192.168.255.255이다.

 앞의 8비트의 값이 192 ~ 223인 IP주소라면(192.168로 시작하는 개인 IP 제외), 클래스 C로 판단할 수 있으므로 앞의 24비트가 네트워크 주소이며, 뒤의 8비트가 호스트 주소로 판단할 수 있다. 그리고 네트워크 주소와 브로드캐스트 주소를 고려해야 한다.

 예를 들어 210.0.0.0인 IP주소가 있으면, 클래스 C로 판단할 수 있으므로 앞의 24비트가 네트워크 주소이며, 뒤의 8비트가 호스트 주소로 판단할 수 있다. 호스트 주소 비트에 전부 0으로 설정된 210.0.0.0은 네트워크 주소로 사용하고 호스트 주소 비트에 전부 1로 설정된 210.0.0.255는 브로트캐스트 주소로 사용해야 한다. 따라서 C클래스로 210.0.0.0을 할당받으면 호스트에게 할당할 수 있는 IP개수는 (2^8)-2개가 된다.

 

 네트워크 주소는 하나의 네트워크를 통칭하기 위한 주소이며, 브로드캐스트 주소는 특정 네트워크에 속하는 모든 호스트 갖게 되는 주소로 동일 네트워크에 있는 모든 클라이언트에게 데이터를 보내기 위해 사용한다.

 3 - 2. 넷마스크 & 서브넷마스크

 넷마스크는 IP주소에서 네트워크 주소 부분의 비트를 1로 설정된 값을 의미한다. 예를 들어 IP가 a.b.c.d라고할 때, 클래스 A라면 넷마스크의 값은 255.0.0.0이고, 클래스 B라면 넷마스크의 값은 255.255.0.0, 클래스 C라면 255.255.255.0이 된다.

 넷마스크의 값을 구하는 이유는 넷마스크 값과 IP값을 bit and연산(&)을 하면 네트워크 주소를 알아낼 수 있기 때문이다.

 

 더 나아가서 서브넷마스크도 존재한다. 서브넷마스크는 서브네팅을 할 때, 서브넷 네트워크로 분할하기 위해 사용된다. 설명이 어렵지만, 예시를 들어 설명하면 아래와 같다.

 

 기존의 클래스 A, 클래스 B, 클래스 C의 경우 호스트의 개수가 정해져 있으므로, 정해진 IP를 효율적으로 배분이 매우 어렵다. 예를 들어, IP가 100개 필요한 α회사, IP가 60개 필요한 β회사, IP가 60개 필요한 γ회사가 있다고 가정하면, 회사마다 클래스C의 IP주소를 할당해줄 때, IP주소의 낭비가 심하게 발생한다. 이러면 하나의 클래스 C 타입 IP주소를 서브네팅하기위해 적절한 서브넷 마스크를 사용하여 각 회사에 알맞은 서브넷 네트워크로 IP를 분할한다.

 

 클래스 C의 경우에는 넷마스크 값이 255.255.255.0이다. 할당된 IP주소가 a.b.c.0이라면 a.b.c.0/24로 표현한다. /24는 앞의 24비트가 네트워크 주소 부분이라는 의미이다. 여기서 호스트 주소 한 비트만 더 네트워크 주소로 사용하면 할당된 IP주소를 두 부분으로 나눌 수 있다. 즉, a.b.c.0/25와 a.b.c.128/25로 나눠진다. 나눠진 부분은 각 (2^7)-2개의 IP를 호스트에게 할당할 수 있다. 여기서 서브넷마스크는 두 부분 다 255.255.255.128이다.

 

 그 후에 a.b.c.128/25부분에서 호스트 주소 한 비트만 더 네트워크 주소로 사용하면, a.b.c.128/26과 a.b.c.192/26으로 나눌 수 있다. 나눠진 부분은 각 (2^6)-2개의 IP를 호스트에게 할당할 수 있으며, 서브넷마스크는 두 부분 다 255.255.255.192다. 위의 α회사, β회사, γ회사에 각각 a.b.c.0, a.b.c.128, a.b.c.192 IP를 할당하고, 서브넷마스크는 각각 255.255.255.128, 255.255.255.192, 255.255.255.192를 사용하면 C클래스 하나로 IP수요가 각각 100, 60, 60인 곳에 분배할 수 있다. 이런 방식을 서브네팅이라 한다. 그리고 서브네팅을 통해 서브넷마스크로 분할된 네트워크를 서브넷 네트워크라 하고, 예시는 각각 a.b.c.0/25, a.b.c.128/26, a.b.c.192/26으로 표현한다.

 

 클래스 C뿐만 아니라 클래스 A, 클래스 B에도 동일한 원리로 적용할 수 있다.

 3 - 3. DNS (Domain Name System)

 도메인 이름을 네트워크 주소로 변환하기 위해 사용한다. 쉽게 설명하면, 사람이 쉽게 기억하는 도메인 이름을 IP주소로 변환해 준다. 53번 포트는 DNS 프로토콜이 사용하는 포트이다.

 

 DNS 설정은 아래의 표를 참고하면 좋다.

운영주체 기본 DNS 보조 DNS
SK브로드밴드 210.220.163.82 219.250.36.130
KT 168.126.63.1 168.126.63.2
LG유플러스 164.124.107.9 203.248.242.2
LG헬로비전 180.182.54.1 180.182.54.2
구글 8.8.8.8 8.8.4.4
시만텍 199.85.126.10 199.85.127.10

 3 - 4. OSI 7계층

OSI 7계층

 OSI 7계층은 위의 표와 같다. 단위의 PDU는 Protocol Data Unit의 줄임말로, 데이터의 전송 단위이다.

 3 - 5. 네트워크 모드: NAT, Host-Only, Bridge

 강의에서 배웠던 모드로는 NAT, Host, Bridge 모드가 있었다. 그림으로 표현하면 아래와 같다.

 

 NAT: 가상머신을 제어하는 프로그램이 DHCP서버를 사용하여, 내부 네트워크 대역을 할당하는 방식이다.

 Host-only: 외부와 단절된 내부 네트워크를 구성하는 방식이다.

 Bridged: 공유기로부터 IP를 할당받아서 호스트와 동일한 네트워크 대역의 IP를 갖는 방식이다.

 

 VMware를 통한 실습에서는 Bridge모드로 변경하는 것과 다시 NAT모드로 변경하는 것을 해 보았다. 

 

 Bridge모드는 가상머신에서 Network Adapter 부분을 Bridged로 변경해주고, 부팅한 후에 nmtui로 호스트 IP와 게이트웨이 등의 정보를 변경해준다.

 

 NAT모드의 변경은 4. VMware NAT IP 변경 방법을 참고하는 것을 추천한다.

 3 - 6. 프로토콜 정리

 프로토콜은 컴퓨터와 컴퓨터 사이에 메시지를 전달하는 과정이다. 프로토콜의 종류는 OSI 7계층마다 다양하게 존재한다. 관제의 경우 네트워크 계층의 취약점을 주로 다루며, 몇 년 전에 유행한 log4j는 응용 프로그램의 취약점이라고 한다.

 

 [네트워크 계층]

 ICMP: 네트워크 장치에서 네트워크 통신 문제를 진단하는 데 사용하는 네트워크 계층 프로토콜이다. ping이 사용다.

 IGMP: 여러 장치가 하나의 IP 주소를 공유하여 모두 동일한 데이터를 수신할 수 있도록 하는 네트워크 계층 프로토콜이다.

 

 [전송 계층]
 TCP: 높은 신뢰성, 데이터 흐름 제어, 연결 설정과 해제
 UDP: 비신뢰성, 빠른 전송 시간

 [응용 계층]
 FTP: 21번 포트로 제어, 20번 포트로 파일 전송 (메시지가 평문이라 보안에 취약하다)
 ssh(22): 옛날에는 느려서 잘 안썼다.
 telnet(23): 평문으로 전달하며 보안에 취약
 SMTP(25): 메일 주고받을 때 프로토콜
 DNS(53): 도메인 이름 주소
 HTTP(80): 인터넷 서비스를 위한 프로토콜
 RPC(111): netstat 명령어에서 사용(> netstat -ano)
 SNMAP(161): 네트쿼으 관리와 모니터리을 위한 프로토콜
 DHCP(67, 68): 제한시간이 있는 IP할당 프로토콜

4. VMware NAT IP 변경 방법

 처음 VMware에서 Edit -> Virtual Network Editor 에서 관리자 권한으로 Change Settings를 실행한다.

 4 - 1. subnet IP 세팅

 Virtual Network Editor 하단에 Subnet IP와 Subnet mask를 설정한다. 3 - 1 IP주소 체계를 읽고 개인 IP 주소 범위로 설정하는 것을 추천한다.

 4 - 2. NAT Settings

 Gateway IP는 변경한 Subnet IP와 Subnet mask를 고려하여 남은 Host IP중 브로드캐스트 IP로 할당할 IP를 고려하여 설정한다.

 위의 예제에서는 서브넷IP와 서브넷마스크가 10.10.10.0이고 255.255.255.0이다. 따라서 호스트에게 할당할 수 있는 IP는 10.10.10.0 ~ 10.10.10.255 이다. 하지만 10.10.10.0는 네트워크 주소로 사용되고 10.10.10.255는 브로드캐스트 주소로 사용할 것이다.

 게이트웨이 IP는 브로드캐스트 주소에서 Host부분에 -1을 한 10.10.10.254나 네트워크 주소에서 Host부분에 +1을 한 10.10.10.1중 하나를 사용하면 된다.

 

 잘 이해가 되지 않는다면 3 - 2. 넷마스크 & 서브넷마스크를 읽어보자.

 4 - 3. DHCP Settings

 DHCP 부분에서는 네트워크 주소와 게이트웨이 주소 사이의 범위를 넣어주면 된다. 위의 예제에서는 10.10.10.1 ~ 10.10.10.253 범위지만, 좀 더 안정적으로 범위를 지정했다.

 그 후에는 Virtual Network Editor 창에서 Apply를 누르면 적용된다.

 

 NAT 모드를 유지하면서 Subnet IP를 변경하는 경우에 가상머신에서 아래의 명령어를 입력하면 IP주소를 재할당 받을 수 있다.

 

 IP재할당 리눅스 $ sudo dhclient [LAN카드 이름(ens33)]

 IP재할당 윈도우 > ipconfig /renew

5. 터미널에서 Mysql 사용 방법

규칙 1. 명령어는 대소문자 구별을 하지 않지만, 변수이름은 대소문자를 구별한다.

규칙 2. 명령어는 ;와야 한 명령으로 인식한다.

 

(접속)

$ sudo mysql -u root

 

> USE mysql; # mysql DB로 설정됨
> SHOW DATABASES; # 데이터베이스들을 출력
> SHOW TABLES; # 테이블들을 출력
> CREATE DATABASE TestDB1; # TestDB1 데이터베이스를 생성
> USE TestDB1; # 데이터베이스를 실행
> CREATE TABLE test_1 (
-> name VARCHAR(15),
-> phone VARCHAR(10)); # 테이블 생성
> SHOW tables; # 테이블 조회
> desc test_1; # test_1 테이블 세부사항 조회
> INSERT INTO test_1 (name, phone) VALUES ("user1", "1111-1111"); # 데이터 추가
> INSERT INTO test_1 (name, phone) VALUES ("user2", "2222-2222");
> INSERT INTO test_1 (name, phone) VALUES ("user3", "2222-1111");
> SELECT name, phone FROM test_1; # 데이터 조회
> SELECT * FROM test_1;
> SELECT * FROM test_1 WHERE name="user2";
> SELECT * FROM test_1 WHERE phone LIKE "%1111";
> UPDATE test_1 SET phone="3333-4444" WHERE name="user2"; # 데이터 업데이트
> DELETE FROM test_1 WHERE name="user2"; # 데이터 삭제
> DROP TABLE test_1; # 테이블 삭제
> SHOW TABLES;
> DROP DATABASE TestDB1; # 데이터베이스 삭제
> SHOW DATABASES;

6. Docker

 6 - 1. Docker의 개념

여기 3. Kubernetes에서 컨테이너 배포 방식의 기술 중 하나이다.

 

Docker의 원리는 리눅스 커널에서 chroot, namespace, cgroup의 기능을 사용한다.

 

 chroot는 CPU자원, 메모리자원, 네트워크대역 등을 프로세스 그룹 단위로 할당하는 리눅스 커널의 기능이다.

 namespace는 프로세스와 그 프로세스의 자식 프로세스들을 특정 그룹으로 관리하는 기능이다. 외부 namespace에 있는 프로세스가 특정 내부의 namespace에 있는 자식 프로세스에 접근하지 못하도록 한다.

 cgroup은 프로세스에 할당하는 자원을 제한하는 기능이다.

 

Docker의 구조는 아래와 같다.

 

Docker client = Docker 컨테이너를 실행하기 위해서 Docker Daemon 프로세스와 연결하기 위해 사용한다.

Docker Daemon = Docker 컨테이너를 관리하고 Docker Client에서 받은 명령을 실행한다.

Registry = Docker 이미지가 저장된 Public & Private 저장소를 의미한다.

Image = Docker Daemon이 Docker 컨테이너를 생성하기 위한 라이브러리나 프로그램 등이 저장된 파일이다.

Container = 이미지를 통해 생성된 인스턴스를 의미한다.

 

Docker를 사용하기 위해 리눅스에서 설치한 라이브러리는 아래와 같다.

 docker-ce = 엔진
 docker-ce-cil = 클라이언트
 contianerd.io = 컨테이너 런타임

 6 - 2. Docker에서 자주 사용하는 명령어

docker image ls = 설치된 이미지 출력
docker search [이미지 이름] = 이미지 검색
docker pull [이미지 이름] = 이미지 다운로드
docker run -d --name [컨테이너 이름] -p [호스트의 포트]:[컨테이너 포트] [이미지 이름] = 컨테이너 생성 및 실행
(-d옵션은 도커를 빠져나와도 도커가 계속 실행하도록 해 준다.)
docker ps -a = 모든 컨테이너를 보여준다.
docker image rm [이미지 이름] = 이미지 삭제
docker image inspect [이미지 이름] = json타입의 이미지 정보를 출력
docker container inspect [컨테이너 이름] = json타입의 컨테이너 정보를 출력 (실행 중인 컨테이너라 static한 정보를 보여준다.)
docker container stop [컨테이너 이름] = 컨테이너를 멈춘다.
docker container start [컨테이너 이름] = 컨테이너를 실행한다.
docker container rm -f [컨테이너 이름] = 컨테이너를 강제(-f)로 삭제한다.
docker exec -it [컨테이너 이름] [컨테이너에서 명령어 실행] = 도커 내부에서 컨테이터 명령어 실행
docker container run -v [호스트pc경로]:[컨테이너 경로] = 두 경로를 mount
docker cp [컨테이너이름]:[컨테이너 절대경로] [호스트 절대경로] = 컨테이너의 파일을 호스트로 복사
docker cp [호스트 절대경로] [컨테이너이름]:[컨테이너 절대경로] = 호스트의 파일을 컨테이너로 복사

 6 - 3. Docker로 3-Tier 환경 구성

 강사님께서 Web(Nginx), WAS(Tomcat)까지 진행해 주셨지만, 나는 유저 이름이나 컨테이너 이름을 내가 구별하기 쉽도록 작성해서 내가 했던 Web(Nginx), WAS(Tomcat), DB(MariaDB) 연동과정을 작성하였다.

 

 우분투에 도커를 설치하는 과정은 https://docs.docker.com/engine/install/ubuntu/를 참고한다.

 

 명령이 $으로 시작하면 Docker를 설치한 우분투, #으로 시작하면 컨테이너 내부, >으로 시작하면 DB라 생각하면 된다. Docker가 설치된 나의 Ubuntu IP는 10.10.10.8, Nginx 컨테이너 IP는 172.17.0.2, Tomcat 컨테이너 IP는 172.17.0.3, MariaDB 컨테이너 IP는 172.17.0.4이다.

 

 1. Nginx 컨테이너를 실행한다.

 (사전에 /home/tester/docker/nginx/conf/ 안에 default.conf 파일과 /home/tester/docker/nginx/data/ 안에 50x.html, index.html 파일을 넣고 시작했다.)

$ sudo docker run -d --name test_web -p 80:80 -v /home/tester/docker/nginx/conf:/etc/nginx/conf.d -v /home/tester/docker/nginx/data:/usr/share/nginx/html nginx

 여기까지가 윈도우PC의 웹 브라우저에 10.10.10.8로 접속하면, Nginx의 index.html 파일을 참조한 웹 페이지가 열린다.

 

 2. Tomcat 컨테이너를 실행한다.

 (사전에 /home/tester/docker/nginx/webapps/ROOT/ 안에 index.html 파일을 넣고 시작했다.)

$ sudo docker run -d --name test_was -p 8080:8080 -v /home/tester/docker/tomcat/webapps:/usr/local/tomcat/webapps/ tomcat

 

 3. Nginx 설정 및 재시작

$ sudo docker container inspect test_was # WAS의 IP주소를 확인한다.
$ sudo vi /home/tester/docker/nginx/conf/default.conf # location / {...} 안에 proxy_pass http://[WAS의 IP]:8080; 입력
$ sudo docker restart test_web

 여기까지가 윈도우PC의 웹 브라우저에 10.10.10.8로 접속하면, Tomcat의 index.html 파일을 참조한 웹 페이지가 열린다.

 

 4. MariaDB 컨테이너를 실행한다. ( -v 옵션을 사용했지만, 해당 부분에 접근할 필요는 없다.)

$ sudo docker run --detach --name test_db -v /home/tester/docker/mariadb/mysql:/var/lib/mysql --env MARIADB_USER=test_user --env MARIADB_PASSWORD=1234 --env MARIADB_DATABASE=mycl --env MARIADB_ROOT_PASSWORD=admin1234 mariadb
$ sudo docker exec -it test_db /bin/bash

 

 5. MariaDB 컨테이너에서 데이터베이스와 테이블 생성 및 데이터베이스 사용자에게 권한을 부여한다.

 (test_user는 db생성 권한이 없다고해서 root와 MARIADB_ROOT_PASSWORD를 이용했다.)

 (나는 Tomcat 컨테이너의 IP가 172.17.0.3이다. %를 사용하거나 본인의 Tomcat 컨테이너 IP를 사용한다.)

# mariadb -u root -p
> CREATE DATABASE test_database;
> USE test_database;
> CREATE TABLE test_table (
-> uid int,
-> uname varchar(20),
-> pass varchar(128),
-> profile varchar(200),
-> priority int);
> INSERT INTO test_table (uid, uname, pass, profile, priority) VALUES (0, "admin", "admin1234", "관리자", 0);
> INSERT INTO test_table (uid, uname, pass, profile, priority) VALUES (0, "user1", "1111", "행인1", 1);
> INSERT INTO test_table (uid, uname, pass, profile, priority) VALUES (0, "user2", "2222", "행인2", 1);
> INSERT INTO test_table (uid, uname, pass, profile, priority) VALUES (0, "user3", "3333", "행인3", 1);
> USE mysql;
> CREATE user 'db_user'@'172.17.0.3' identified by '1234';
> GRANT all privileges on test_database.test_table to 'db_user'@'172.17.0.3';
> FLUSH privileges;

 

 6. 배운 Docker 명령어를 잘 이용하여 Tomcat 컨테이너의 /bin/bash를 실행하고 컨테이너 내부에서 아래의 명령을 실행한다. (tomcat 컨테이너에 jdbc 라이브러리만 넣어준다.)

# wget https://downloads.mysql.com/archives/get/p/3/file/mysql-connector-java-5.1.40.tar.gz
# tar xzf mysql-connector-java-5.1.40.tar.gz
# cp mysql-connector-java-5.1.40/mysql-connector-java-5.1.40-bin.jar /usr/local/tomcat/lib/

 

 

 7. WAS의 login.jsp 파일을 작성한다. (나는 main.html파일을 login.jsp가 생성해주므로 login.jsp만 추가로 작성하였다.)

 

 $ vi /home/tester/docker/tomcat/webapps/ROOT/index.html

<html>
        <head>
                <meta charset="utf-8">
                <title>로그인 화면</title>
        </head>
        <body>
                <form method="POST" action="./login.jsp">
                        아이디 : <input type="text" name="id" value = ""/> </br>
                        비밀번호 : <input type="password" name="password" value = ""/> <p>
                        <input type="submit" value="로그인">
                </form>
        </body>
</html>

 

 $ vi /home/tester/docker/tomcat/webapps/ROOT/login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="java.sql.*" %>
<%@ page import="java.io.PrintWriter" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<%
String uid = request.getParameter("id");
String pwd = request.getParameter("password");
String DB_URL = "jdbc:mysql://172.17.0.4:3306/test_database";
String DB_USER = "db_user";
String DB_PASSWORD= "1234";
String sel = "";
ResultSet rs = null;
Connection conn;
Statement stmt;

try {
        Class.forName("com.mysql.jdbc.Driver");
        conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
        stmt = conn.createStatement();
        //사용자 정보 조회
        sel = "select * from test_table where uname='" + uid + "' and pass='" + pwd + "'";
        rs = stmt.executeQuery(sel);

        String fileName = "main.html";
        String filePath = application.getRealPath("./" + fileName);
        PrintWriter writer = new PrintWriter(filePath);
        if (rs.next()) {
                String main_html_contents = "<html><head><meta charset='utf-8'><title>로그인 성공</title></head><body><div>" + uid + "님 반갑습니다.</div></body></html>";
                writer.println(main_html_contents);
                writer.close();
                Thread.sleep(800); // main.html이 생성되기 전에 연결되는 것을 방지
                response.sendRedirect("main.html");
        }
        else {
                response.sendRedirect("index.html");
        }
        conn.close();
} catch(Exception e) {
        out.println(e.getMessage());
}
%>

 작성을 완료했다면, $ sudo docker restart test_was 명령을 통해 Tomcat 컨테이너를 재시작한다.

 

 8. 결과

Docker가 설치된 Ubuntu의 IP주소는 10.10.10.8이다.

  VMware에서 가상머신 3개로 3-Tier를 구동하는 것보다 가상머신 1개에서 도커로 3-Tier를 구동하는 것이 더 편한 것 같다.

7. 후기

 네트워크 리눅스뿐만 아니라 다양한 공부를 할 수 있었다. 강사님이 우리에게 최대한 많이 알려주려는 노력을 하시는 것이 크게 보였다. 다른 곳에서는 최소 3일이나 5일로 예정을 잡는 교육을 반나절이나 하루 만에 알려주셔서 열정이 뛰어나셨다는 것을 알 수 있었다. 진도가 빨라서 전공자인 나조차 이해, 메모, 실습 3개를 같이 하느라 강의를 여유있게 따라가기 어려웠다.

 하지만 많은 것을 알려주신 만큼 복습을 하면서 약간 부족했던 부분을 더 공부할 수 있었다. 특히 강의 중간에 가끔 주시는 미션은 실력을 향상는데 큰 도움이 되었다고 생각한다.

 

 추가로 이번 일주일 내용을 한 페이지에 몰아서 작성하다가 페이지를 나눌 생각을 했다. 왜하면 배운 내용 하나하나가 깊게 들어가면 한 페이지를 충분히 채울 내용이기 때문이다. 현재 페이지를 삭제하고 리눅스 기본 기술과 네트워크 기본 기술로 나누려 했지만, VMware와 Docker관련 내용도 같이 포함되어 있어서 둘로 나누는 것은 어려울 것 같다. 리눅스 기본 기술, 네트워크 기본 기술, VMware 관련, Docker 관련으로 나누기에는 너무 많은 페이지가 생성되어서 해당 방향성은 아니라고 생각한다. 아직은 한 페이지로 관리할 생각이다.

8. 참고자료

https://en.wikipedia.org/wiki/Unix_filesystem

 

Unix filesystem - Wikipedia

From Wikipedia, the free encyclopedia Directory structure used by a Unix-like operating system "Usr" redirects here. For other uses, see USR. "Unix file system" redirects here. For UFS, a specific file system used by many Unix and Unix-like operating syste

en.wikipedia.org

https://en.wikipedia.org/wiki/Classful_network

 

Classful network - Wikipedia

From Wikipedia, the free encyclopedia Early system for organizing the IPv4 address space Map of the prototype Internet in 1982, showing 8-bit-numbered networks (ovals) only, interconnected by routers (rectangles). A classful network is an obsolete network

en.wikipedia.org

https://ko.wikipedia.org/wiki/%EB%8F%84%EB%A9%94%EC%9D%B8_%EB%84%A4%EC%9E%84_%EC%8B%9C%EC%8A%A4%ED%85%9C

 

도메인 네임 시스템 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 도메인 네임 시스템(Domain Name System, DNS)은 호스트의 도메인 이름을 호스트의 네트워크 주소로 바꾸거나 그 반대의 변환을 수행할 수 있도록 하기 위해 개발되었

ko.wikipedia.org

http://wiki.hash.kr/index.php/OSI_7_%EA%B3%84%EC%B8%B5

 

OSI 7 계층 - 해시넷

OSI 7 계층(OSI 7 Layer) OSI 7 계층(OSI 7 Layer)는 네트워크 프로토콜이 통신하는 구조를 7개의 계층으로 분리하여 각 계층간 상호 작동하는 방식을 정해 놓은 것 이다. 이는 ISO(국제표준화기구)에서 개

wiki.hash.kr

https://docs.docker.com/engine/install/ubuntu/

 

Install Docker Engine on Ubuntu

Jumpstart your client-side server applications with Docker Engine on Ubuntu. This guide details prerequisites and multiple methods to install Docker Engine on Ubuntu.

docs.docker.com