브리지 네트워크 (Bridge Network):

Docker에서 기본적으로 제공되는 네트워크 모드입니다.
컨테이너가 독립적인 IP 주소를 가지며, 호스트와는 브리지 네트워크를 통해 통신합니다.

 

bridge는 Docker의 기본 네트워크 드라이버 중 하나입니다. Docker가 설치되면 기본적으로 생성되는 네트워크 모드로, 개별 컨테이너들이 독립된 네트워크 네임스페이스에서 동작하게 합니다. 이렇게 하면 컨테이너 간의 네트워크 통신이 보안적으로 격리됩니다.

bridge 네트워크에 대한 주요 특징은 다음과 같습니다:

  • 격리: 각 컨테이너는 독립된 네트워크 네임스페이스를 가지기 때문에 서로 격리됩니다.
  • 자동 IP 할당: Docker의 내장 DHCP 서버에 의해 자동으로 IP 주소가 할당됩니다. 보통 172.17.0.x 범위의 주소가 기본으로 사용됩니다.
  • 포트 매핑: 호스트 시스템의 특정 포트를 컨테이너의 특정 포트에 매핑(포워딩)할 수 있습니다. 예를 들어, 호스트의 8080 포트를 컨테이너의 80 포트에 매핑할 수 있습니다.
  • 컨테이너 간 통신: 같은 bridge 네트워크에 있는 컨테이너끼리는 IP 주소를 통해 서로 통신할 수 있습니다.

그러나 bridge 네트워크 모드에는 몇 가지 제한사항도 있습니다

  • 외부 네트워크와의 통신은 NAT(Network Address Translation)를 통해 이루어지기 때문에 성능 오버헤드가 있을 수 있습니다.
  • 호스트와 컨테이너 간의 통신을 위해서는 포트 매핑이 필요합니다.
  • 다른 호스트에 있는 컨테이너와의 통신은 기본적으로 지원되지 않습니다.
  • 이러한 제한사항 때문에 복잡한 배포나 여러 호스트 간의 통신이 필요한 경우에는 overlay, macvlan 등의 다른 네트워크 드라이버를 사용하기도 합니다.

 

호스트 네트워크 (Host Network):

컨테이너가 호스트의 네트워크 네임스페이스를 사용합니다.
컨테이너는 호스트의 IP 주소와 포트를 직접 사용할 수 있습니다.

반응형

'Programming > Linux' 카테고리의 다른 글

docker-compose  (0) 2023.10.28
Nginx  (0) 2023.08.16
Redis  (0) 2023.08.10
kafka 설치(우분투 기존)  (0) 2023.07.31
ELK연습  (0) 2023.07.30

여러 도커간의 디펜던시를 설정해서 빌드하고 띄우는 일을 할 수 있다.

 

용어

서비스 (Service)

Docker Compose 내에서 쓰이는 개념으로, 도커 컨테이너의 구성 및 실행 방법을 정의한 것.
서비스는 하나의 컨테이너일 수도 있고, 동일한 이미지를 기반으로 하는 여러 컨테이너의 집합일 수도 있다.

예를 들어, docker-compose.yml 파일에 다음과 같은 정의가 있다면:

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
  database:
    image: mysql:5.7
    environment:
      - MYSQL_ROOT_PASSWORD=my-password

여기에서 web과 database는 각각 하나의 서비스.
이 경우, 각 서비스는 각각 하나의 컨테이너를 생성하지만, 필요에 따라 한 서비스에서 여러 컨테이너를 생성할 수도 있습니다 (예: 스케일링 목적으로).


결국, "서비스"는 Docker Compose에서 응용 프로그램의 한 부분 (예: 웹 서버, 데이터베이스)을 나타내며, 이 서비스를 구성하는 데 필요한 설정과 함께 도커 이미지 정보를 포함합니다.

 

사용방법

docker-compose build:

이 명령어는 docker-compose.yml 파일에 정의된 모든 서비스의 이미지를 빌드합니다.
docker-compose.yml 파일에서 build: 섹션을 사용하여 Dockerfile의 위치나 빌드 컨텍스트 등을 지정한 서비스에 대해서만 이 명령어를 사용해야 합니다.


docker-compose up -d:

위에서 빌드한 이미지들의 실행 인스턴스인 컨테이너들을 만들어 실행
-d 옵션은 "detached mode"를 의미하며, 백그라운드에서 컨테이너를 실행하라는 것을 의미
이미지가 없다면 빌드도 시도하기 때문에 docker-compose build 없이 이것만 실행해도 되긴 하나,

코드 변경시 재빌드해주진 않기 때문에 코드 변경이 있었다면 build후 up해야 한다.

 

docker-compose down -v:

up과 반대로 컨테이너들 중단하고 없애준다.

-v하면 관련 데이터 볼륨도 제거해준다.

여기서 데이터 볼륨(Data Volume)은 Docker 컨테이너 파일 시스템의 일부를 호스트 시스템에 저장하는데 사용되는 매커니즘으로, 컨테이너간 데이터를 공유하는 공유폴더 개념으로 쓰이거나 데이터를 영구적으로 저장할수 있게 해준다.

그 예시로는 (DB, 로그, config file등이 있다)

 

 

docker-compose ps

docker-compose로 관리되는 컨테이너들의 현재 상태와 관련된 정보를 조회

 

다음내용 확인가능

  • 서비스 상태 확인: docker-compose up 명령을 사용하여 여러 서비스를 시작한 후, 각 서비스의 컨테이너가 올바르게 실행 중인지, 혹은 중지된 상태인지를 확인하기 위해 사용됩니다.
  • 문제 진단: 서비스에 문제가 발생했을 때, 어떤 컨테이너가 문제를 일으키고 있는지 확인하기 위해 사용될 수 있습니다. 예를 들어, 컨테이너가 계속 재시작되는 경우, docker-compose ps를 통해 해당 컨테이너의 상태를 확인할 수 있습니다.
  • 포트 정보 확인: 각 컨테이너에서 어떤 포트가 호스트와 연결되었는지 확인하려 할 때 사용됩니다.
  • 스케일링 확인: docker-compose up --scale 명령을 사용하여 서비스의 인스턴스 수를 조정한 경우, 현재 실행 중인 인스턴스 수를 확인하기 위해 사용됩니다.
  • 컨테이너 이름 확인: docker-compose로 시작된 컨테이너들은 특정한 네이밍 규칙을 가지고 있습니다. 이 이름을 확인하기 위해 docker-compose ps를 사용할 수 있습니다.

아래는 예시

               Name                             Command               State                                  Ports
--------------------------------------------------------------------------------------------------------------------------------------------------
table-walkthrough_data-generator_1   /docker-entrypoint.sh            Up
table-walkthrough_grafana_1          /run.sh                          Up      0.0.0.0:3000->3000/tcp,:::3000->3000/tcp
table-walkthrough_jobmanager_1       /docker-entrypoint.sh stan ...   Up      6123/tcp, 0.0.0.0:8082->8081/tcp,:::8082->8081/tcp
table-walkthrough_kafka_1            start-kafka.sh                   Up      0.0.0.0:9092->9092/tcp,:::9092->9092/tcp
table-walkthrough_mysql_1            docker-entrypoint.sh --def ...   Up      3306/tcp, 33060/tcp
table-walkthrough_taskmanager_1      /docker-entrypoint.sh task ...   Up      6121/tcp, 6122/tcp, 6123/tcp, 8081/tcp
table-walkthrough_zookeeper_1        /bin/sh -c /usr/sbin/sshd  ...   Up      0.0.0.0:2181->2181/tcp,:::2181->2181/tcp, 22/tcp, 2888/tcp, 3888/tcp
sevity@sevityubuntu:~/workspace/flink-playgrounds/table-walkthrough$
반응형

'Programming > Linux' 카테고리의 다른 글

docker network  (0) 2023.10.29
Nginx  (0) 2023.08.16
Redis  (0) 2023.08.10
kafka 설치(우분투 기존)  (0) 2023.07.31
ELK연습  (0) 2023.07.30

주 역할

웹서버/캐시/로드밸런서/리버스프록시

 

SSL Termination

클라이언트와는 https통신을 하면서 백단 서버들과는 http(gRPC포함)통신을 하여, 복호화 부담을 줄이는 기능

 

실전꿀팁

여기가면 실제로 많이 사용되는 Nginx설정을 보고 적용할 수 있다.

반응형

'Programming > Linux' 카테고리의 다른 글

docker network  (0) 2023.10.29
docker-compose  (0) 2023.10.28
Redis  (0) 2023.08.10
kafka 설치(우분투 기존)  (0) 2023.07.31
ELK연습  (0) 2023.07.30

설치 운영

우분투에서 설치

sudo apt-get update
sudo apt-get install redis-server

 

트러블슈팅

docker안에서 host의 redis에 접근하도록 하기

실행할때 다음처럼 --network host만 붙여주면 된다.

#!/bin/bash

PORT=$1

docker run \
  --network host \
  -e SPRING_APPLICATION_JSON='{"server":{"port":'"$PORT"'}}' \
  -p $PORT:$PORT \
  auth-service

 

설계관점

 

읽는 경우: Look aside Cache

Cache에 있으면 Cache에서 가져오고 없으면 DB에서 읽고 Cache 업데이트

 

쓰는경우: Write Back

Cache에 저장하고 주기적으로 모아서 DB에 배치업데이트. 

반응형

'Programming > Linux' 카테고리의 다른 글

docker-compose  (0) 2023.10.28
Nginx  (0) 2023.08.16
kafka 설치(우분투 기존)  (0) 2023.07.31
ELK연습  (0) 2023.07.30
스팍 - 실습 - 웹서버 세션분석  (0) 2023.07.30

kafka란

RabbitMQ와 같은 메시지 미들웨어.

LinkedIn에서 개발되어 현재는 Apache Software Foundation의 일부인 오픈 소스 메시지 스트리밍 플랫폼.
대량의 실시간 데이터 스트리밍을 처리하는 데 초점을 맞추고 있고, 높은 처리량, 데이터 복제, 분산 처리 등을 지원

이를 통해 대규모 데이터를 실시간으로 처리할 수 있다.

MSA간 통신에도 자주 쓰임

 

브로커: Kafka에서 메시지를 처리하는 서버

  • 카프카에서는 이벤트를 구분하기 위한 단위로 '토픽'을 사용하며 파일시스템의 디렉토리와 비슷한 개념으로 이해 가능
    • 토픽은 게시/구독 메시징 시스템에서 흔하게 볼 수 있다.
      • 카프카 외적으로는 비슷한 개념에 대해 채널, 큐, 스트림이라는 용어를 사용하기도 함
        • 개인적으로는 채널이 더 직관적이네
    • 프로듀서는 데이터를 '토픽'에 넣고, 컨슈머는 '토픽'에서 데이터를 읽는다.
    • 이러한 토픽은 카프카 클러스터내에서 데이터를 분류하고 구독자가 관심있는 메시지만 구독할 수 있도록 해주는 중요한 역할
    • 카프카 클러스터 전체가 하나의 토픽만 사용한다면 생략도 가능한가? > NO.
  • 토픽의 데이터는 파티션에 분산 저장되며 각 파티션은 순서 유지가 되는 메시지의 로그로 구성
  • 하나의 브로커는 여러 파티션의 데이터를 저장할 수 있으며, 반대로 하나의 파티션도 여러 브로커에 복제될 수 있음에 주의
  • 파티션의 개수는 토픽의 병렬처리 능력을 결정

리더 브로커: 특정 메시지그룹(파티션)의 처리를 담당하는 서버. Kafka에서 각 데이터 파티션에는 하나의 리더 브로커가 있음

  • 리더 브로커는 파티션과 1:1의 관계를 가지며 하나의 파티션을 여러 브로커가 처리할경우 하나만 리더이고 나머지는 팔로워로 동작

 

ZooKeeper

  • 일종의 비서역할로 서버들의 상태관리나 역할분배를 Kafka를 위해서 수행함. Kakfa설치시 같이 설치됨.
  • 또는 일종의 '중앙 데이터 저장소' 역할. Kafka 시스템 내의 여러 서버들이 ZooKeeper를 통해 필요한 정보 공유하고 동기화.
  • 특정 서버에 문제가 생기면 이 정보가 ZooKeeper에 기록되고 다른 서버들이 이를 확인하여 적절히 대응

 

kafka설치과정

Java설치

카프카는 Java기반이므로 java jdk가 안깔렸으면 깔아준다.

sudo apt update
sudo apt install default-jdk

사용자계정에 종속된 설치보다는 여러명이 쓸 수 있도록 아래 처럼 전용 유저를 생성해주는게 좋다.

sudo adduser kafka
sudo adduser kafka sudo

카프카는 자바 기반이므로 jar파일을 받아서 설정해준다. apt등의 패키지 매니저를 사용하면 예전버전일수 있으므로 다운로드해서 해보자.

mkdir ~/Downloads
curl "https://downloads.apache.org/kafka/3.5.1/kafka_2.13-3.5.1.tgz" -o ~/Downloads/kafka.tgz
mkdir /opt/kafka && cd /opt/kafka
tar -xvzf ~/Downloads/kafka.tgz --strip 1


#kafka디렉토리 소유권을 kafka사용자로 변경
sudo useradd kafka -m
sudo chown -R kafka:kafka /opt/kafka

/opt/kafka에 설치했으며, /opt 디렉토리는 선택적인(add-on) 애플리케이션 SW패키지를 위한 곳으로 여러사용자가 이용하는 라이브러리인 경우 선호되는 경로다.

 

zookeeper설정

zookeeper는 kafka와 독립적으로 실행되며, 비슷한 설정 매커니즘을 갖는다.

zookeeper설정파일 수정

sevity@sevityubuntu:/opt/kafka/config$ cat zookeeper.properties
# the directory where the snapshot is stored.
dataDir=/var/cache/zookeeper
# the port at which the clients will connect
clientPort=2181
# disable the per-ip limit on the number of connections since this is a non-production config
maxClientCnxns=0
# Disable the adminserver by default to avoid port conflicts.
# Set the port to something non-conflicting if choosing to enable this
admin.enableServer=false
# admin.serverPort=8080

다른 부분은 그냥 두었고, dataDir은 /var/cache 밑에 두어 휘발되지 않도록 설정했다. (기본은 /tmp 밑에 있었던듯)

이를 위해 다음과 같은 권한 설정을 했다.

sudo mkdir /var/cache/zookeeper
sudo chown kafka:kafka /var/cache/zookeeper
sudo chmod 700 /var/cache/zookeeper

 

zookeeper에 대해 systemctl에 등록해서 부팅시 마다 실행되도록 하기위해 다음 파일 작성

sudo vi /etc/systemd/system/zookeeper.service

[Unit]
Description=Apache Zookeeper server
Documentation=http://zookeeper.apache.org
Requires=network.target remote-fs.target
After=network.target remote-fs.target

[Service]
Type=simple
User=kafka
ExecStart=/opt/kafka/bin/zookeeper-server-start.sh /opt/kafka/config/zookeeper.properties
ExecStop=/opt/kafka/bin/zookeeper-server-stop.sh
Restart=on-abnormal

[Install]
WantedBy=multi-user.target

# 그 다음 systemctl을 통해 시작하고 재부팅 시에도 항상 실행되도록 설정
sudo systemctl start zookeeper
sudo systemctl enable zookeeper

kafka에 대해서도 마찬가지로 작성

sudo vi /etc/systemd/system/kafka.service

[Unit]
Description=Apache Kafka server
Documentation=http://kafka.apache.org
Requires=zookeeper.service
After=zookeeper.service

[Service]
Type=simple
User=kafka
ExecStart=/home/kafka/kafka/bin/kafka-server-start.sh /home/kafka/kafka/config/server.properties
ExecStop=/home/kafka/kafka/bin/kafka-server-stop.sh
Restart=on-abnormal

[Install]
WantedBy=multi-user.target

# 그 다음 systemctl을 통해 시작하고 재부팅 시에도 항상 실행되도록 설정
sudo systemctl start kafka
sudo systemctl enable kafka

 

트러블 슈팅

서버로그 실시간 모니터링

tail -f /opt/kafka/logs/server.log

 

jps로 kafka가 잘 실행되고 있는지 확인(QuorumPeerMain과 Kafka가 떠있으면OK)

su - kafka
jps
109092 Jps
108186 QuorumPeerMain(Zookeeper의 시작점)
108573 Kafka

 

 

토픽 메시지가 잘 수신되는지 확인하는 방법

가장 기본적으로는 9092포트를 리슨하고 있는지 확인

sevity@sevityubuntu:/opt/kafka/config$ lsof -i :9092
COMMAND    PID   USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
java    168958 sevity  116u  IPv6 1324110      0t0  TCP sevityubuntu:46330->sevityubuntu:9092 (ESTABLISHED)
java    168958 sevity  117u  IPv6 1320714      0t0  TCP sevityubuntu:46336->sevityubuntu:9092 (ESTABLISHED)

 

GetOffsetSell을 통해 특정 토픽에 게시된 메지시수를 확인

sevity@sevityubuntu:/opt/kafka$ bin/kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list localhost:9092 --topic iis_log --time -1
iis_log:0:4043038

kafka-console-consumer.sh를 사용하여 특정 토픽의 메시지 수신상황을 실시간으로 확인

$ bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic iis_log --from-beginning
{"@timestamp":"2023-08-01T01:18:34.407Z","@metadata":{"beat":"filebeat","type":"_doc","version":"8.9.0"},"agent":{"version":"8.9.0","ephemeral_id":"98df9137-96e3-4653-b353-2821eebde875","id":"cf839823-29c8-4619-b9c4-85e90804e50e","name":"SEVITY-PC","type":"filebeat"},"ecs":{"version":"8.0.0"},"log":{"file":{"path":"c:\\inetpub\\logs\\LogFiles\\W3SVC1\\u_ex230801.log"},"offset":16076},"message":"2023-08-01 01:17:24 192.168.0.6 GET /wiki/doku.php id=Advice%20To%20Relieve%20Your%20Acid%20Reflux%20Signs%20and%20symptoms 80 - 196.245.181.117 Mozilla/5.0+(X11;+Ubuntu;+Linux+x86_64;+rv:114.0)+Gecko/20100101+Firefox/114.0 http://sevity.com/ 200 0 0 1182","input":{"type":"log"},"host":{"mac":["00-15-83-EA-2C-EE","00-23-24-63-E7-E3","02-50-41-00-00-01","88-36-6C-F7-D9-04","88-36-6C-F7-D9-06","88-36-6C-F7-D9-07"],"hostname":"sevity-pc","name":"sevity-pc","architecture":"x86_64","os":{"family":"windows","name":"Windows 10 Enterprise","kernel":"10.0.19041.3208 (WinBuild.160101.0800)","build":"19045.3208","type":"windows","platform":"windows","version":"10.0"},"id":"dbb18b3d-fb42-49ec-b731-f430dd2f3fd5","ip":["fe80::a30b:d99a:f7ed:2bac","192.168.100.15","fe80::a4ce:c09a:ea91:8a9","169.254.142.88","fe80::9c93:77c8:66bd:b6c5","169.254.55.217","fe80::dd77:ec13:69c4:6922","169.254.56.104","fe80::310a:1b3d:e9a3:431c","192.168.0.6","fe80::2c27:d03a:a322:765b","169.254.236.36"]}}

 

반응형

'Programming > Linux' 카테고리의 다른 글

Nginx  (0) 2023.08.16
Redis  (0) 2023.08.10
ELK연습  (0) 2023.07.30
스팍 - 실습 - 웹서버 세션분석  (0) 2023.07.30
스팍(Spark) 설치  (0) 2023.07.30

먼저 IIS서버에 Filebeat를 깔아서 우분투 분석 서버에 kafka전송을 한다.

반응형

'Programming > Linux' 카테고리의 다른 글

Redis  (0) 2023.08.10
kafka 설치(우분투 기존)  (0) 2023.07.31
스팍 - 실습 - 웹서버 세션분석  (0) 2023.07.30
스팍(Spark) 설치  (0) 2023.07.30
하둡 - 실습 - 웹서버 세션분석  (0) 2023.07.29

먼저 하둡버전을 보고 오길 권한다.

스팍 설치에 관한 부분은 여기 참조.

우리는 하둡버전과 비슷하게 IIS웹서버를 분석해서 map - reduce과정을 통해 IP별 접근 시간및 URL을 정리해서 볼 것이다. 오리지널 웹서버 로그는 대략 다음과 같으며,

sevity@sevityubuntu:~/workspace/hadoop_sevity.com/session_analysis$ cat ../iis_logs/* | head
#Software: Microsoft Internet Information Services 10.0
#Version: 1.0
#Date: 2015-09-06 08:32:43
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken
2015-09-06 08:32:43 127.0.0.1 GET / - 80 - 127.0.0.1 Mozilla/5.0+(Windows+NT+10.0;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/45.0.2454.85+Safari/537.36 - 200 0 0 211
2015-09-06 08:32:43 127.0.0.1 GET /iisstart.png - 80 - 127.0.0.1 Mozilla/5.0+(Windows+NT+10.0;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/45.0.2454.85+Safari/537.36 http://127.0.0.1/ 200 0 0 2
2015-09-06 08:32:43 127.0.0.1 GET /favicon.ico - 80 - 127.0.0.1 Mozilla/5.0+(Windows+NT+10.0;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/45.0.2454.85+Safari/537.36 http://127.0.0.1/ 404 0 2 2

map-reduce를 거친 결과는 대략 다음과 같을 것이다.

sevity@sevityubuntu:~/workspace/hadoop_spark/session_analysis$ cat session_output_merged.txt | head
157.55.39.90
[[(datetime.datetime(2016, 6, 7, 20, 44, 21), '/')], [(datetime.datetime(2016, 6, 8, 4, 20, 31), '/menu_wonilnet.asp'), (datetime.datetime(2016, 6, 8, 4, 20, 43), '/menu_friend.asp')], [(datetime.datetime(2019, 9, 16, 23, 58, 6), '/menu_friend.asp')], [(datetime.datetime(2021, 8, 17, 15, 8, 50), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 8, 17, 17, 36, 23), '/menu_wonilnet.asp'), (datetime.datetime(2021, 8, 17, 17, 36, 24), '/menu_friend.asp')], [(datetime.datetime(2021, 8, 18, 1, 53, 52), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 8, 19, 2, 40, 48), '/wiki/doku.php')], [(datetime.datetime(2021, 8, 19, 6, 45, 32), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 8, 20, 10, 0, 31), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 8, 21, 3, 55, 36), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 8, 21, 4, 55, 13), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 8, 23, 6, 49, 26), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 8, 24, 1, 45, 47), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 8, 24, 9, 58, 34), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 8, 25, 11, 55, 24), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 8, 26, 8, 22, 7), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 8, 26, 13, 56, 19), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 8, 27, 21, 59, 24), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 8, 28, 20, 3, 46), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 8, 28, 23, 51, 21), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 8, 29, 18, 40, 40), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 8, 29, 20, 6, 8), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 8, 31, 1, 38, 52), '/wiki/doku.php')], [(datetime.datetime(2021, 8, 31, 5, 29, 5), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 8, 31, 6, 28, 20), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 9, 2, 0, 32, 17), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 9, 2, 16, 19, 20), '/wiki/lib/exe/detail.php')], [(datetime.datetime(2021, 9, 9, 3, 2, 43), '/menu_wonilnet.asp'), (datetime.datetime(2021, 9, 9, 3, 2, 45), '/menu_friend.asp')], [(datetime.datetime(2021, 9, 16, 7, 52, 4), '/wiki/doku.php')]]
138.197.96.197
[[(datetime.datetime(2017, 2, 15, 17, 21, 24), '/'), (datetime.datetime(2017, 2, 15, 17, 21, 26), '/menu_wonilnet.asp'), (datetime.datetime(2017, 2, 15, 17, 21, 26), '/board/dhtml_logo.js')]]
104.236.164.185
[[(datetime.datetime(2017, 11, 28, 11, 45, 56), '/')]]
181.213.93.231
[[(datetime.datetime(2018, 1, 30, 13, 1, 24), '/hndUnblock.cgi'), (datetime.datetime(2018, 1, 30, 13, 1, 28), '/tmUnblock.cgi'), (datetime.datetime(2018, 1, 30, 13, 1, 32), '/moo'), (datetime.datetime(2018, 1, 30, 13, 1, 36), '/'), (datetime.datetime(2018, 1, 30, 13, 1, 42), '/getcfg.php'), (datetime.datetime(2018, 1, 30, 13, 1, 49), '/getcfg.php')]]
117.80.147.63
[[(datetime.datetime(2018, 2, 14, 8, 13, 12), '/')]]

실습을 위한 디렉토리 구조는 대략 다음과 같다.

sevity@sevityubuntu:~/workspace/hadoop_spark$ tree -L 3
.
├── iis_logs (여기에 분석하려는 웹로그 파일들이 있습니다. 실제로는 수없이 많음)
│   ├── u_ex230101.log
│   ├── u_ex230102.log
│   └── u_ex230103.log
├── session_analysis
│   ├── session_output
│   │   ├── part-00001
│   │   ├── part-00002
│   │   ├── part-00003
│   │   └── _SUCCESS
│   ├── session_output_merged.txt
│   └── spark_session_analysis.py(우리가 작성할 python 코드의 위치)
└── spark_test

다음과 같이 spark_session_analysis.py를 작성하자.

여기서 중요한 점은 다음과 같다.

  • 스팍은 하둡과 다르게 하나의 파일에서 map과 reduce를 모두 수행한다.
  • 각 동작은 함수호출 형태로 진행되며,
  • 아래에서 reduce에 해당하는 함수는 groupByKey()이다.
from pyspark import SparkConf, SparkContext
from datetime import datetime, timedelta
from pyspark.sql import SparkSession

def parse_log_line(line):
    try:
        parts = line.strip().split()
        if len(parts) != 15:
            return None

        date_time = parts[0] + " " + parts[1]
        date_time = datetime.strptime(date_time, '%Y-%m-%d %H:%M:%S')
        url = parts[4]
        ip = parts[8]  # changed from parts[2] to parts[8] to use the client IP

        return (ip, (date_time, url))
    except:
        return None

def calculate_sessions(group):
    ip, data = group
    data = list(data)
    data.sort(key = lambda x: x[0])
    sessions = []
    session = [data[0]]
    for i in range(1, len(data)):
        if data[i][0] - session[-1][0] > timedelta(seconds=1800):
            sessions.append(session)
            session = [data[i]]
        else:
            session.append(data[i])
    sessions.append(session)
    return (ip, sessions)


# Spark configuration
# [*]하면 모든 코어 사용
conf = SparkConf().setMaster('local[*]').setAppName('Log Analysis')
sc = SparkContext(conf=conf)

log_lines = sc.textFile('hdfs://localhost:9000/logs/u_ex*')
parsed_lines = log_lines.map(parse_log_line).filter(lambda x: x is not None)
grouped_by_ip = parsed_lines.groupByKey()
sessions = grouped_by_ip.flatMap(calculate_sessions)
sessions.saveAsTextFile('hdfs://localhost:9000/session_output')

다음 명령을 통해 실행하고 결과를 확인한다.

# hdfs에 reduce결과를 쌓을 곳을 clean-up해준다. 
hdfs dfs -rm -r /session_output

# 로컬파일시스템에 복사해올 경로도 clean-up해준다.
rm -rf session_output
rm -f session_output_merged.txt

# python 파일을 실행한다. spark-submit을 통해 실행하면 4040포트를 통해 웹에서 진행상황 확인가능
$SPARK_HOME/bin/spark-submit spark_session_analysis.py 2>&1 | tee r.txt 

# HDFS에서 로컬파일시스템으로 결과 폴더 복사
hadoop fs -get /session_output .

# 위의 폴더구조에서 볼 수 있듯 병렬처리 때문에 결과파일이 여러개로 분리돼 있는데 합쳐준다.
# 합치고 로컬파일시스템으로 복사하는 것까지.
hadoop fs -getmerge hdfs://localhost:9000/session_output ./session_output_merged.txt

# 위의 방법대신 python코드내에서 다음 방법으로 머지해도 된다.
# 단 스팍을 써서 머지하는 방법인 만큼 메모리가 터질수도 있으니 주의
sessions.coalesce(1).saveAsTextFile('hdfs://localhost:9000/session_output')
반응형

'Programming > Linux' 카테고리의 다른 글

kafka 설치(우분투 기존)  (0) 2023.07.31
ELK연습  (0) 2023.07.30
스팍(Spark) 설치  (0) 2023.07.30
하둡 - 실습 - 웹서버 세션분석  (0) 2023.07.29
하둡 - 실습 - 웹서버로그분석  (0) 2023.07.29

기본개념

스파크(Spark)는 하둡과 마찬가지로 자바(Java) 기반의 빅 데이터 처리 프레임워크입니다. 
하지만 스파크는 자바 외에도 스칼라(Scala), 파이썬(Python), R 등 여러 언어를 지원합니다.

스파크의 핵심 코드는 스칼라로 작성되어 있습니다. 스칼라는 함수형 프로그래밍과 객체지향 프로그래밍을 모두 지원하는 현대적인 다중 패러다임 프로그래밍 언어입니다. 스칼라는 JVM(Java Virtual Machine) 위에서 동작하므로 자바와 호환성이 좋습니다.

스파크는 또한 파이스파크(PySpark)라는 인터페이스를 통해 파이썬에서도 사용할 수 있습니다. 이는 데이터 과학자들이 파이썬으로 빅 데이터 처리를 수행할 수 있게 해주는 큰 장점입니다. 

 

 

설치과정

가장 간단하게는 그냥 pip install pyspark 하면 깔린다.

하지만, 먼저 설치한 하둡하고 연결하려면 아래 과정을 거치면 된다.

 

먼저 공식홈페이지에 가서 Pre-built for Apache Hadoop을 선택하고 다운로드를 받는다.

아래는 해당 다운로드 링크를 wget으로 받는 과정을 설명한다.

아래처럼 wget으로 받고 압축을 풀어준다.

cd /opt/spark
sudo wget https://dlcdn.apache.org/spark/spark-3.4.1/spark-3.4.1-bin-hadoop3.tgz
sudo tar -xvzf spark-3.4.1-bin-hadoop3.tgz

그다음 ~/.bashrc파일에 아래 3줄을 추가하고 source ~/.bashrc로 적용해준다.

export SPARK_HOME=/opt/spark/spark-3.4.1-bin-hadoop3
export PATH=$PATH:$SPARK_HOME/bin:$SPARK_HOME/sbin
export PYSPARK_PYTHON=/usr/bin/python3

그다음 설정파일에 대한 설정을 해준다.

cd /opt/spark/spark-3.4.1-bin-hadoop3/conf
cp spark-env.sh.template spark-env.sh

#spark-env.sh에 아래 두 줄 추가
export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop
export SPARK_HOME=$SPARK_HOME

#추가한 내용 반영
source spark-env.sh

그 다음 pyspark을 설치해준다.

pip3 install pyspark

 

 

설치가 잘 됐는지 테스트

다음 명령어를 통해 spark shell이 잘 뜨는지 확인(scala> 프롬프트가 뜨면 성공)

$SPARK_HOME/bin/spark-shell

다음 파이선 스크립트를 통해 하둡 HDFS와 잘 연동되는지 확인

from pyspark.sql import SparkSession

spark = SparkSession.builder.getOrCreate()
df = spark.read.text("hdfs://localhost:9000/test.txt")
df.show()
# 먼저 hdfs로 test.txt를 복사해준다.
$ cat test.txt
hello spark
$ hdfs dfs -put test.txt /

# 그다음 다음명령으로 test.py 수행
$ $SPARK_HOME/bin/spark-submit test.py
+-----------+
|      value|
+-----------+
|hello spark|
+-----------+

위의 spark-submit을 통한 실행시 test.py가 끝나기 전에 4040포트로 웹접속을 하면 다음과 같이 웹으로 경과확인이 가능하다!

반응형

'Programming > Linux' 카테고리의 다른 글

ELK연습  (0) 2023.07.30
스팍 - 실습 - 웹서버 세션분석  (0) 2023.07.30
하둡 - 실습 - 웹서버 세션분석  (0) 2023.07.29
하둡 - 실습 - 웹서버로그분석  (0) 2023.07.29
하둡(Hadoop)  (0) 2023.07.29

먼저 필요한경우 하둡을 포맷하고 초기화 해준다.

stop-dfs.sh  # 분산 파일 시스템(HDFS) 중지
stop-yarn.sh # 리소스 관리자(YARN)중지
hdfs namenode -format
start-dfs.sh
# YARN은 Hadoop의 주요 컴포넌트 중 하나로, 클러스터 리소스 관리 및 job scheduling을 담당하고 있습니다.
# 따라서, 만약 MapReduce 작업을 수행할 예정이라면, 이 명령어를 통해 YARN을 시작해야 합니다.
start-yarn.sh

# 나같은 경우 아래를 해야하는 경우가 있었다.
rm -rf /hadoop/data/*

# 헬스체크
hadoop fsck /

 

내 웹서버 로그 샘플은 다음과 같음

evity@sevityubuntu:~/workspace/hadoop_sevity.com/session_analysis$ cat ../iis_logs/* | head
#Software: Microsoft Internet Information Services 10.0
#Version: 1.0
#Date: 2015-09-06 08:32:43
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken
2015-09-06 08:32:43 127.0.0.1 GET / - 80 - 127.0.0.1 Mozilla/5.0+(Windows+NT+10.0;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/45.0.2454.85+Safari/537.36 - 200 0 0 211
2015-09-06 08:32:43 127.0.0.1 GET /iisstart.png - 80 - 127.0.0.1 Mozilla/5.0+(Windows+NT+10.0;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/45.0.2454.85+Safari/537.36 http://127.0.0.1/ 200 0 0 2
2015-09-06 08:32:43 127.0.0.1 GET /favicon.ico - 80 - 127.0.0.1 Mozilla/5.0+(Windows+NT+10.0;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/45.0.2454.85+Safari/537.36 http://127.0.0.1/ 404 0 2 2

이중에서 다음 컬럼을 뽑아서 map-reduce를 해보도록 하자.

날짜와 시간 (2015-09-06 08:32:43)
클라이언트 IP (c-ip)
요청된 URL (cs-uri-stem)

먼저 매핑과정을 통해 다음처럼 클라이언트 IP별로 30분 단위로 세션으로 묶어서 URL들을 뽑는다.

119.207.72.161  {"start_time": "2020-10-03 00:14:47", "end_time": "2020-10-03 00:14:48", "duration": 1.0, "url_list": ["/favicon.ico", "/board/dhtml_logo.js", "/menu_wonilnet.asp", "/", "/css/common.css"]}
66.249.65.54    {"start_time": "2020-10-03 00:27:31", "end_time": "2020-10-03 00:27:31", "duration": 0.0, "url_list": ["/wiki/doku.php"]}
80.82.70.187    {"start_time": "2020-10-03 01:59:09", "end_time": "2020-10-03 01:59:09", "duration": 0.0, "url_list": ["/cache/global/img/gs.gif"]}
139.59.95.139   {"start_time": "2020-10-03 02:11:31", "end_time": "2020-10-03 02:11:31", "duration": 0.0, "url_list": ["/"]}

그다음 리듀스 과정을 통해 IP별로 총 체류시간과 url_list를 묶어준다.

66.249.64.128   {"total_duration": 1694.0, "url_list": ["/menu_wonilnet.asp", "/menu_friend.asp", "/robots.txt", "/", "/menu_wonilnet_newImage.asp", "/favicon.ico"], "start_time": "2017-09-03 04:19:21", "end_time": "2018-07-29 20:43:11"}
66.249.70.30    {"total_duration": 1694.0, "url_list": ["/menu_wonilnet.asp", "/menu_friend.asp", "/robots.txt", "/wiki/doku.php", "/wiki/lib/tpl/dokuwiki/images/favicon.ico", "/", "/wiki/feed.php", "/wiki/lib/exe/js.php", "/wiki/lib/exe/css.php", "/css/common.css", "/wiki/lib/exe/detail.php", "/favicon.ico", "/wiki/lib/exe/fetch.php"], "start_time": "2017-07-26 01:31:14", "end_time": "2022-02-01 09:49:49"}
2.37.132.159    {"total_duration": 1689.0, "url_list": ["/"], "start_time": "2018-03-23 22:13:24", "end_time": "2018-03-23 22:43:34"}

폴더구조는 다음과 같으며, 이번 프로젝트의 현재 디렉토리는 session_analysis이다.

sevity@sevityubuntu:~/workspace/hadoop_sevity.com$ tree -L 1
.
├── iis_logs
├── ip_cnt
└── session_analysis

mapper.py를 다음과 같이 작성한다.

sevity@sevityubuntu:~/workspace/hadoop_sevity.com/session_analysis$ cat mapper.py
#!/usr/bin/env python3

import sys
import json
import codecs
from datetime import datetime, timedelta
import logging

logging.basicConfig(stream=sys.stderr, level=logging.ERROR)

previous_ip = None
url_list = []
start_time = None
end_time = None
session_timeout = timedelta(seconds=1800)  # 1800 seconds = 30 minutes

def reset_variables():
    global url_list, start_time, end_time
    url_list = []
    start_time = None
    end_time = None

# Using codecs to get stdin with a fallback in case of a UTF-8 decoding error
stdin = codecs.getreader('utf-8')(sys.stdin.buffer, errors='ignore')

for line in stdin:
    try:
        parts = line.strip().split()
        if len(parts) != 15:
            continue

        date_time = parts[0] + " " + parts[1]
        date_time = datetime.strptime(date_time, '%Y-%m-%d %H:%M:%S')

        ip = parts[8]  # changed from parts[2] to parts[8] to use the client IP
        url = parts[4]

        # If there is a previous ip and the current ip is different or a session timeout has occurred
        if previous_ip and (previous_ip != ip or (date_time - end_time) > session_timeout):
            print('%s\t%s' % (previous_ip, json.dumps({"start_time": str(start_time), "end_time": str(end_time), "duration": (end_time - start_time).total_seconds(), "url_list": list(set(url_list))})))
            reset_variables()

        if not start_time or date_time < start_time:
            start_time = date_time
        if not end_time or date_time > end_time:
            end_time = date_time

        url_list.append(url)
        previous_ip = ip

    except Exception as e:
        logging.error(f"Error processing line: {line.strip()}, Error: {e}")

# Print the last session
if previous_ip:
    print('%s\t%s' % (previous_ip, json.dumps({"start_time": str(start_time), "end_time": str(end_time), "duration": (end_time - start_time).total_seconds(), "url_list": list(set(url_list))})))

reducer.py를 다음과 같이 작성한다.

sevity@sevityubuntu:~/workspace/hadoop_sevity.com/session_analysis$ cat reducer.py
#!/usr/bin/env python3

import sys
import json

previous_ip = None
total_duration = 0.0
url_list = []
start_time = None
end_time = None

for line in sys.stdin:
    ip, session_info = line.strip().split('\t')
    session_info = json.loads(session_info)

    if previous_ip and previous_ip != ip:
        print('%s\t%s' % (previous_ip, json.dumps({"total_duration": total_duration, "url_list": list(set(url_list)), "start_time": start_time, "end_time": end_time})))

        total_duration = 0.0
        url_list = []
        start_time = None
        end_time = None

    if not start_time or session_info["start_time"] < start_time:
        start_time = session_info["start_time"]
    if not end_time or session_info["end_time"] > end_time:
        end_time = session_info["end_time"]

    total_duration += float(session_info["duration"])
    url_list.extend(session_info["url_list"])

    previous_ip = ip

if previous_ip:
    print('%s\t%s' % (previous_ip, json.dumps({"total_duration": total_duration, "url_list": list(set(url_list)), "start_time": start_time, "end_time": end_time})))

다음명령을 통해 map-reduce과정을 병렬로 진행한다.

hdfs dfs -rm -r /output && \
	hadoop jar $HADOOP_HOME/share/hadoop/tools/lib/hadoop-streaming-*.jar    \
    -file ~/workspace/hadoop_sevity.com/session_analysis/mapper.py     \
    -mapper 'python3 mapper.py'     \
    -file ~/workspace/hadoop_sevity.com/session_analysis/reducer.py     \
    -reducer 'python3 reducer.py'     \
    -input /logs/* -output /output \
    2>&1 | tee r.txt

결과를 HDFS에서 로컬파일시스템으로 가져온다.

rm -rf output && hadoop fs -get /output .

다음 python파일을 통해 duration역순으로 정렬한다.

import json
import sys

def get_duration(json_str):
    data = json.loads(json_str)
    return data.get('total_duration', 0)

lines = sys.stdin.readlines()

# 각 줄을 total_duration 값에 따라 정렬
lines.sort(key=lambda line: get_duration(line.split('\t', 1)[1]), reverse=True)

for line in lines:
    print(line, end='')
python3 sort.py < output/part-00000 > result.txt

result.txt를 보면 다음과 같다.

45.61.187.81    {"total_duration": 186353.0, "url_list": ["/"], "start_time": "2022-07-23 09:13:06", "end_time": "2022-08-22 20:57:09"}
127.0.0.1       {"total_duration": 161933.0, "url_list": ["/w/lib/tpl/dokuwiki/images/favicon.ico", "/wonilnet_pub/2010-06-09_192759_resize.png", "/w/lib/exe/css.php", "/image/top_menu_icon.gif", "/upgsvr/service.exe", "/favicon.ico", "/index.asp", "/w/lib/tpl/dokuwiki/images/pagetools-sprite.png", "/scrape", "/w/lib/tpl/dokuwiki/images/search.png", "/wiki/doku.php", "/w/lib/tpl/dokuwiki/images/usertools.png", "/", "/images/next5.gif", "/wonilnet_pub/2010-06-09_192656_resize.png", "/w/lib/tpl/dokuwiki/images/button-php.gif", "/image/rightconer_shadow.gif", "/menu_wonilnet_dbwork.asp", "/iisstart.png", "/w/lib/images/external-link.png", "/tc.js", "/w", "/css/common.css", "/a.php", "/images/num1_on_a.gif", "/w/lib/tpl/dokuwiki/images/button-donate.gif", "/w/lib/tpl/dokuwiki/images/button-html5.png", "/menu_friend.asp", "/w/lib/tpl/dokuwiki/images/button-dw.png", "/announce.php", "/w/doku.php", "/w/lib/tpl/dokuwiki/images/logo.png", "/announce", "/images/nonext.gif", "/images/num5_off.gif", "/image/garo_shadow.gif", "/scrape.php", "/image/sero_shadow.gif", "/w/lib/tpl/dokuwiki/images/button-css.png", "/images/num2_off.gif", "/menu_wonilnet.asp", "/favicon.png", "/image/leftconer_shadow.gif", "/images/num4_off.gif", "/images/num3_off.gif", "/image/line02.gif", "/board/dhtml_logo.js", "/w/lib/tpl/dokuwiki/images/page-gradient.png", "/w/lib/images/license/button/cc-by-sa.png", "/w/lib/exe/js.php", "/pub/02111401.jpg", "/w/lib/exe/indexer.php"], "start_time": "2015-09-06 08:32:43", "end_time": "2021-10-13 12:56:47"}
45.61.188.237   {"total_duration": 121316.0, "url_list": ["/"], "start_time": "2022-10-03 20:31:14", "end_time": "2022-10-26 20:10:54"}
64.62.252.174   {"total_duration": 102775.0, "url_list": ["/stock/test1/main.cpp", "/menu_wonilnet.asp", "/menu_friend.asp", "/stock/test1/id.cpp", "/robots.txt", "/wiki/lib/exe/css.php", "/wiki/lib/exe/opensearch.php", "/wiki/feed.php", "/wiki/doku.php", "/wiki/lib/exe/", "/wiki/lib/exe/indexer.php", "/wiki/lib/exe/js.php", "/wiki/lib/exe/mediamanager.php", "/wiki/", "/wiki/lib/exe/detail.php", "/wiki/lib/exe/fetch.php"], "start_time": "2022-08-11 04:54:40", "end_time": "2023-07-06 16:23:29"}

 

이 과정을 통해 다음과 같이 해킹을 시도하는 서버접근을 발견할 수 있었다.

124.173.69.66   {"total_duration": 1685.0, "url_list": ["/xw1.php", "/9510.php", "/link.php", "/sbkc.php", "/index.php", "/phpmyadmin/scripts/setup.php", "/xmlrpc.php", "/jsc.php.php", "/phpmyadmin3333/index.php", "/phpNyAdmin/index.php", "/hm.php", "/411.php", "/hhhhhh.php", "/key.php", "/92.php", "/pma/scripts/db___.init.php", "/aojiao.php", "/1/index.php", "/3.php", "/slider.php", "/plus/tou.php", "/g.php", "/ssaa.php", "/sss.php", "/lala-dpr.php", "/605.php", "/admin/index.php", "/plus/yunjitan.php", "/d.php", "/boots.php", "/win1.php", "/hell.php", "/uploader.php", "/images/vuln.php", "/error.php", "/que.php", "/099.php", "/aa.php", "/12345.php", "/666.php", "/api.php", "/plus/90sec.php", "/xiao.php", "/fusheng.php", "/xiaoxi.php", "/plus/ma.php", "/paylog.php", "/321/index.php", "/qwqw.php", "/qiangkezhi.php", "/liangchen.php", "/mysql.php", "/ganshiqiang.php", "/images/stories/cmd.php", "/xiong.php", "/datas.php", "/xixi.php", "/aaa.php", "/awstatstotals/awstatstotals.php", "/conflg.php", "/php2MyAdmin/index.php", "/think.php",

 

반응형

'Programming > Linux' 카테고리의 다른 글

스팍 - 실습 - 웹서버 세션분석  (0) 2023.07.30
스팍(Spark) 설치  (0) 2023.07.30
하둡 - 실습 - 웹서버로그분석  (0) 2023.07.29
하둡(Hadoop)  (0) 2023.07.29
Docker 설치, 초기설정, 명령어가이드  (0) 2023.07.17

어떤 IP에서 가장많이 접속했는지 확인

필자는 개인 IIS 웹서버를 운영하고 있음

다음을 통해 웹서버에서 하둡이 설치된 우분투 리눅스로 가져오고 HDFS로 복사(파일 복사가 RDB에서는 insert에 해당한다)

# 웹서버에서 하둡이설치된 리눅스로 로그파일들 복사
scp linowmik@secsm.org@192.168.0.6:/inetpub/logs/LogFiles/W3SVC1/* ./iis_logs

# HDFS로 복사
hdfs dfs -put ./iis_logs/* /logs/

# 위 복사가 너무 오래걸리면 아래 명령을 통해 진행상황 모니터링 가능
cd $HADOOP_HOME/logs
sudo tail -f $(ls -Art $HADOOP_HOME/logs | tail -n 1)
# 위명령어 설명은 다음과 같음
# ls -Art $HADOOP_HOME/logs: $HADOOP_HOME/logs 디렉토리 내의 파일을 날짜별로 오름차순 정렬합니다. -Art 옵션은 -A (숨겨진 파일 포함), -r (역순), -t (수정 시간별 정렬) 옵션을 동시에 사용하는 것입니다.
# tail -n 1: 파일 리스트 중에서 가장 최신의 파일 (리스트의 마지막 항목)을 선택합니다.
# tail -f: 선택한 파일의 내용을 실시간으로 출력합니다. -f 옵션은 'follow'의 약자로, 파일의 내용이 변경될 때마다 이를 반영하여 출력합니다.

로그가 어떤 형식인지 잠시 확인한다

sevity@sevityubuntu:~/workspace/hadoop_sevity.com$ cat iis_logs/*.log | head
#Software: Microsoft Internet Information Services 10.0
#Version: 1.0
#Date: 2015-09-06 08:32:43
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken
2015-09-06 08:32:43 127.0.0.1 GET / - 80 - 127.0.0.1 Mozilla/5.0+(Windows+NT+10.0;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/45.0.2454.85+Safari/537.36 - 200 0 0 211
2015-09-06 08:32:43 127.0.0.1 GET /iisstart.png - 80 - 127.0.0.1 Mozilla/5.0+(Windows+NT+10.0;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/45.0.2454.85+Safari/537.36 http://127.0.0.1/ 200 0 0 2
2015-09-06 08:32:43 127.0.0.1 GET /favicon.ico - 80 - 127.0.0.1 Mozilla/5.0+(Windows+NT+10.0;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/45.0.2454.85+Safari/537.36 http://127.0.0.1/ 404 0 2 2

#으로 시작하는 라인을 제외하면 날짜 시간 IP 등의 순임을 알 수 있다.

  • 2023-03-23 00:20:47 : 요청이 발생한 날짜와 시간.
  • 192.168.0.6 : 서버의 IP 주소 또는 호스트 이름.
  • GET : HTTP 요청 방법. 이 경우, 클라이언트는 서버로부터 정보를 요청하고 있습니다.
  • /wiki/doku.php : 클라이언트가 요청한 리소스의 경로.
  • id=learning_rate&do=login&sectok=bac058c83457f1bfade853577f509baf : 요청에 전달된 파라미터입니다.
  • 80 : 사용된 포트 번호. HTTP의 기본 포트는 80입니다.
  • - : 이 필드는 일반적으로 RFC 1413 ident 프로토콜을 통해 확인된 원격 사용자 이름을 나타냅니다. 여기서 "-"는 이 정보가 사용 불가능하다는 것을 의미합니다.
  • 216.244.66.237 : 클라이언트의 IP 주소.
  • Mozilla/5.0+(compatible;+DotBot/1.2;++https://opensiteexplorer.org/dotbot;+help@moz.com) : 사용자 에이전트. 이는 클라이언트가 사용하는 웹 브라우저 또는 봇을 설명합니다. 이 경우에는 DotBot이라는 봇이 서버에 요청을 보냈습니다.
  • - : 이 필드는 일반적으로 "referrer" URL을 나타냅니다. 여기서 "-"는 이 정보가 사용 불가능하다는 것을 의미합니다.
  • 200 : HTTP 상태 코드. 200은 성공을 의미합니다.
  • 0 : 서브 상태 코드. 이는 서버에 따라 다르게 해석될 수 있습니다.
  • 0 : Win32 상태 코드. 이는 서버에 따라 다르게 해석될 수 있습니다.
  • 1068 : 서버가 클라이언트에게 보낸 바이트 .

 

이를위한 mapper.py를 다음처럼 작성한다.

import sys
import logging

# Set up logging
# logging.basicConfig(filename="mapper.log", level=logging.DEBUG)
# 아래처럼 하면 하둡로그랑 섞여서 나와서 디버깅할때 좋다.
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)


# Ignore bad characters
for line in sys.stdin.buffer:
    try:
        line = line.decode('utf-8', 'ignore')
    except UnicodeDecodeError as e:
        logging.error(f"Error decoding line: {line.strip()}, Error: {e}")
        continue

    try:
        data = line.strip().split(" ")
        if len(data) == 15:
            date, time, s_ip, cs_method, cs_uri_stem, cs_uri_query, s_port, cs_username, c_ip, cs_user_agent, cs_referer, sc_status, sc_substatus, sc_win32_status, time_taken = data
            logging.debug(f"Client IP: {c_ip}, Count: 1")
            print("{0}\t{1}".format(c_ip, 1))
    except Exception as e:
        # 예외 발생 시 로그 기록
        logging.error(f"Error processing line: {line.strip()}, Error: {e}")

관심있는 IP와 카운트1을 결과로 출력함을 알 수 있다. (이러면 하둡이 스트리밍하여 Reduce쪽으로 넘긴다)

 

이제 아래와 같이 reducer.py를 작성하여 IP별 카운트를 집계한다.

#!/usr/bin/env python3

import sys
import logging

# Set up logging
logging.basicConfig(filename="reducer.log", level=logging.DEBUG)

last_key = None
running_total = 0
key = None

try:
    for input in sys.stdin:
        key, value = input.strip().split("\t", 1)
        if last_key == key:
            running_total += int(value)
        else:
            if last_key:
                logging.debug(f"Key: {last_key}, Running Total: {running_total}")
                print("{0}\t{1}".format(last_key, running_total))
            running_total = int(value)
            last_key = key

    if last_key == key and key is not None:
        logging.debug(f"Key: {last_key}, Running Total: {running_total}")
        print("{0}\t{1}".format(last_key, running_total))

except Exception as e:
    # 예외 발생 시 로그 기록
    logging.error(f"Error processing input: {e}")

다음명령을 통해 map-reduce를 수행(RDB에서 SELECT에 해당한다)

# 이전실행 클린업
hdfs dfs -rm -r /output

# 실행
hadoop jar $HADOOP_HOME/share/hadoop/tools/lib/hadoop-streaming-*.jar \
	-file ~/workspace/hadoop_sevity.com/mapper.py \
    -mapper 'python3 mapper.py' \
    -file ~/workspace/hadoop_sevity.com/reducer.py \
    -reducer 'python3 reducer.py' \
    -input /logs/* -output /output 2>&1 | tee r.txt

그다음 결과를 hdfs에서 로컬로 가져와서 결과 보기

# 로컬로 가져오기
hadoop fs -get /output .

# IP카운트(2번째컬럼) 역순으로 정렬
sort -k2,2nr -t $'\t' output/* > sorted_output.txt

# 결과보기(상위 10개)
cat sorted_output.txt | head
216.244.66.237	69027
192.168.0.1	27738
211.189.165.105	20114
64.62.252.174	13246
119.207.72.84	8959
211.53.177.20	6565
66.249.82.88	5636
66.249.82.89	5632
66.249.82.90	5312
194.110.203.7	5157

# 가장 많이 접속한 IP에 대한 정보를 역추적해서 보기
grep -m 10 216.244.66.237 iis_logs/* | head
iis_logs/u_ex180725.log:2018-07-25 05:40:56 192.168.0.2 GET /robots.txt - 80 - 216.244.66.237 Mozilla/5.0+(compatible;+DotBot/1.1;+http://www.opensiteexplorer.org/dotbot,+help@moz.com) - 404 0 2 499
iis_logs/u_ex180725.log:2018-07-25 05:44:26 192.168.0.2 GET / - 80 - 216.244.66.237 Mozilla/5.0+(compatible;+DotBot/1.1;+http://www.opensiteexplorer.org/dotbot,+help@moz.com) - 200 0 0 641
iis_logs/u_ex180805.log:2018-08-05 02:39:00 192.168.0.2 GET /robots.txt - 80 - 216.244.66.237 Mozilla/5.0+(compatible;+DotBot/1.1;+http://www.opensiteexplorer.org/dotbot,+help@moz.com) - 404 0 2 194
iis_logs/u_ex180805.log:2018-08-05 02:42:02 192.168.0.2 GET / - 80 - 216.244.66.237 Mozilla/5.0+(compatible;+DotBot/1.1;+http://www.opensiteexplorer.org/dotbot,+help@moz.com) - 200 0 0 181
iis_logs/u_ex181027.log:2018-10-27 06:25:55 192.168.0.2 GET /robots.txt - 80 - 216.244.66.237 Mozilla/5.0+(compatible;+DotBot/1.1;+http://www.opensiteexplorer.org/dotbot,+help@moz.com) - 404 0 2 183
iis_logs/u_ex181027.log:2018-10-27 06:35:36 192.168.0.2 GET / - 80 - 216.244.66.237 Mozilla/5.0+(compatible;+DotBot/1.1;+http://www.opensiteexplorer.org/dotbot,+help@moz.com) - 200 0 0 176
iis_logs/u_ex181107.log:2018-11-07 01:04:26 192.168.0.2 GET /robots.txt - 80 - 216.244.66.237 Mozilla/5.0+(compatible;+DotBot/1.1;+http://www.opensiteexplorer.org/dotbot,+help@moz.com) - 404 0 2 448
iis_logs/u_ex181107.log:2018-11-07 01:13:17 192.168.0.2 GET / - 80 - 216.244.66.237 Mozilla/5.0+(compatible;+DotBot/1.1;+http://www.opensiteexplorer.org/dotbot,+help@moz.com) - 200 0 0 668
iis_logs/u_ex190201.log:2019-02-01 21:31:17 192.168.0.2 GET /robots.txt - 80 - 216.244.66.237 Mozilla/5.0+(compatible;+DotBot/1.1;+http://www.opensiteexplorer.org/dotbot,+help@moz.com) - 404 0 2 118
iis_logs/u_ex190201.log:2019-02-01 21:45:12 192.168.0.2 GET / - 80 - 216.244.66.237 Mozilla/5.0+(compatible;+DotBot/1.1;+http://www.opensiteexplorer.org/dotbot,+help@moz.com) - 200 0 0 118
sevity@sevityubuntu:~/workspace/hadoop_sevity.com$
반응형

'Programming > Linux' 카테고리의 다른 글

스팍(Spark) 설치  (0) 2023.07.30
하둡 - 실습 - 웹서버 세션분석  (0) 2023.07.29
하둡(Hadoop)  (0) 2023.07.29
Docker 설치, 초기설정, 명령어가이드  (0) 2023.07.17
vimdiff  (0) 2021.04.07

+ Recent posts