WSL(Windows Subsystem for Linux) Ubuntu CRON Job 사용하기

CRON(Command Run On)이란, Unix System에서 제공하는 Job scheduler를 말한다. CRON은 Shell 명령어들이 주어진 일정에 주기적으로 실행하기 위해서 crontab(CRON Table)이란 것을 참조하고, crontab에는 실행시킬 Job 목록과 일정이 기록되어 있다.

CRON Table

사실, Windows에서도 Task scheduler라는 기능을 사용하면 Scheduling을 얼마든지 할 수 있긴 하다. 하지만 간혹 이미 Linux shell script로 제공되는 경우 등 Linux 환경에서의 작업이 더 유리한 상황인 경우에는 해당 script를 Windows 용으로 변경해야 하는 번거로움이 있다.

이럴때 WSL을 이용하면 좋다. WSL은 Ubuntu환경을 거의 대부분 제공하기 때문에 별도의 Linux 환경을 구성하지 않아도 주어진 Shell Script를 그대로 이용하면 Scheduling이 가능하다.

예를 들어, Linux System에 대한 Health check를 주기적으로 매시간마다 기록해야하는 상황이라고 가정해보자. Linux System이기 때문에 Bash shell script로 작업하는 것이 유리 할 것이다.

먼저, CRON Scehduler가 Backgroud에서 동작하기 위해서 daemon service를 설치 및 실행해야한다.

# Install CRON package
$ sudo apt-get udpate
$ sudo apt-get install cron

# CRON Service start
$ sudo service cron start

CRON이 정상적으로 실행되었다면, 다음으로 Health check를 위한 Script를 준비해야한다. Script는 직접 작성하여도 좋지만, 미리 잘 만들어져서 공개된 Open Source Script를 사용하면 쉽게 작업 할 수 있다.

WSL(Ubuntu-18.04)를 실행시켜 미리 잘 준비된 Script를 가져와 보자.
(Linux health check script는 여기를 참조하였다. Script code는 Apache 2.0 License로 배포되었다.)

$ wget https://tecmint.com/wp-content/scripts/tecmint_monitor.sh

Shell Script가 준비가 되었다면, WSL에서 CRON에 등록하여 사용하기만 하면 된다.
다음 명령어를 실행하면 CRON Table을 편집할 수 있는 편집창이 나온다.

$ crontab -e

아래 Command Code를 그림과 같이 편집창에 실행될 Schedule과 함께 넣어준다.

# monitor script 실행 결과를 result text 파일에 출력한다.
0 * * * * /home/newth/CRON/tecmint_monitor.sh >> /home/newth/CRON/result.txt
CRON Table 편집창

저장하고 나면 CRON Table에 Job Schedule이 등록된 것이다. 등록된 Schedule로 인해서 CRON은 매 시간 정각마다 Command에 입력된 절대경로 shell script를 실행시킬 것이다.

정상적으로 실행 되는지 확인해 보고 싶다면 다음과 같이 syslog를 확인해 보면된다.

$ tail -f /var/log/syslog

CRON Table에 등록한 대로 동작한 결과를 확인 해 볼 수 있다.

$ /var/log$ tail -f syslog

Feb 14 22:45:28 DESKTOP-LM4ALRO crontab[331]: (newth) BEGIN EDIT (newth) --CRON Table 편집 
Feb 14 22:45:33 DESKTOP-LM4ALRO crontab[331]: (newth) END EDIT (newth) --CRON Table 편집 종료
Feb 14 22:45:35 DESKTOP-LM4ALRO crontab[342]: (newth) LIST (newth) --CRON Table 리스트 확인
... 생 략 ...
Feb 14 23:00:00 DESKTOP-LM4ALRO CRON[433]: (newth) CMD (/home/newth/CRON/tecmint_monitor.sh | cat > /home/newth/CRON/result.txt) --CRON Table 실행 Log


Web Crawling with Scrapy(2)

지난 포스트에서는 Scrapy Shell에서 간단한 명령 코드를 이용하여 간단히 Web Crawling을 수행해 보았다.

이번에는 지난 포스트에서 작성한 Shell 명령 코드를 활용하여 Spider Project를 만들어서 데이터를 주기적으로 업데이트 할 수 있는 Crawler 모듈을 만들어 보겠다.

그럼, Spider Project를 만들어 보자.

아래와 같이 Project를 구성할 위치에서 명령어를 실행해보자.

# newsCrawler라는 Spider Project를 만든다.
$ scrapy startproject newsCrawler

명령 실행이 완료 되면, 다음과 같은 메시지가 나오면서 Start Project가 만들어 진것을 확인 할 수 있다.

You can start your first spider with:
    cd newsCrawler
    scrapy genspider example example.com

이제, newsCrawler라고 만든 프로젝트를 이용하여 Crawler 모듈 개발 작업을 시작하면 되는데… 그전에 먼저, Project의 구성에 대해서 간단히 알아보도록 하자.

  • newsCrawler/ # Root Directory
    • scrapy.cfg # 프로젝트 설정 파일
    • newsCrawler/ # 프로젝트 공간
      • __init__.py
      • items.py # Spider가 작업을 완료한 후 반환하는 결과 값의 Schema를 정의하는 파일
      • middlewares.py # Spider가 요청을 보낼 때 process를 제어하는 파일
      • pipelines.py # Spider가 응답을 받았을 때 process를 제어하는 파일
      • settings.py # Spider 실행에 필요한 전반적인 옵션을 설정하는 파일
      • spiders/ # 데이터를 수집 가공하는 Spider(Crawler) 모듈을 개발하는 공간, 여러개의 Spider가 있을 수 있다.
        • __init__py

위 프로젝트 구성을 보면 “nwesCrawler/spider”라는 위치에서 Spider(Crawler)를 개발하면 되는 것을 알 수 있다.

해당 위치로 이동하여 아래와 같이 Spider(Crawler) 생성 명령을 실행해 보자.

# Project의 spiders폴더로 이동하여 newsBot이라는 Spider를 생성한다.
$ cd newsCrawler/spiders
$ scrapy genspider newsBot 'news.daum.net/ranking/popular'

명령 실행이 완료되면 다음과 같이 기본 Template이 생성되었다는 메시지를 확인 할 수 있다.

Created spider 'newsBot' using template 'basic' in module:
  {spiders_module.__name__}.{module}

이제, 만들어진 Template(newsBot.py)에 이전에 만들어둔 Shell 명령 코드를 넣어서 Spiders(Crawler) 모듈 개발 작업을 하면 된다.

import scrapy

class NewsbotSpider(scrapy.Spider):
    name = 'newsBot'
    allowed_domains = ['news.daum.net/ranking/popular']
    start_urls = ['http://news.daum.net/ranking/popular/']

    def parse(self, response):
        # Web Crawling with Scrapy(1) 참고
        titles = response.xpath('//ul[@class="list_news2"]/li/div[2]/strong/a/text()').extract()
        authors = response.xpath('//ul[@class="list_news2"]/li/div[2]/strong/span/text()').extract()
        previews_text = response.xpath('//ul[@class="list_news2"]/li/div[2]/div[1]/span/text()').extract()
        previews_image = response.xpath('//ul[@class="list_news2"]/li/a/img/@src').extract()

        for item in zip(titles, authors, previews_text, previews_image):
            scraped_info = {
                'title': item[0].strip(),
                'author': item[1].strip(),
                'preview_text': item[2].strip(),
                'preview_image': item[3].strip()
            }
            yield scraped_info

개발 작업 완료되었으면, 아래와 같이 newsBot을 실행시켜 보자.

# newsBot 실행하고 결과는 JSON 파일로 지정위치에 출력한다.
$ scrapy crawl newsBot -o ./newsCrawler/json/result.json

실행이 완료되면 결과가 지정된 위치 “newsCrawler/json”에 JSON 파일로 만들어 진 것을 확인 할 수 있다.

그런데 JSON 파일을 열어보면 다음과 같이 Unicode로 결과가 출력되어 데이터가 잘 수집된 것인지 확인 하기가 어렵다.

[
    {
        "title": "\ubb38 \ub300\ud1b5\ub839 \"3\ub2e8\uacc4 \uaca9\uc0c1\uc740 \ub9c8\uc9c0\ub9c9 \uc218\ub2e8..\ubd88\uac00\ud53c\ud558\uba74 \uacfc\uac10\ud788 \uacb0\ub2e8\"",
        "author": "\uacbd\ud5a5\uc2e0\ubb38",
        "preview_text": "[\uacbd\ud5a5\uc2e0\ubb38] \ubb38\uc7ac\uc778 \ub300\ud1b5\ub839\uc740 13\uc77c \ucf54\ub85c\ub09819 \ud655\uc9c4\uc790\uac00 \uae09\ub4f1\uc138\ub97c \ubcf4\uc774\ub294 \uac83\uacfc \uad00\ub828, \u201c\uc9c0\uae08 \ud655\uc0b0\uc138\ub97c \uaebe\uc9c0 \ubabb\ud558\uba74 \uc0ac\ud68c\uc801 \uac70\ub9ac\ub450\uae30 3\ub2e8\uacc4 \uaca9\uc0c1\ub3c4 \uac80\ud1a0\ud574\uc57c \ud558\ub294 \uc911\ub300\ud55c \uad6d...",
        "preview_image": "https://img1.daumcdn.net/thumb/S95x77ht.u/?fname=https%3A%2F%2Ft1.daumcdn.net%2Fnews%2F202012%2F13%2Fkhan%2F20201213154335225ujgt.jpg&scode=media"
    },
    ..... 생략 .....
]

출력 결과를 알아보기 쉽게 한글로 표현하기 위해서는 settings.py에 출력결과가 utf-8로 인코딩될 수 있도록 설정을 추가 해주면 된다.

FEED_EXPORT_ENCODING = 'utf-8'

설정 내용을 저장하고 다시한번 newsBot을 실행 시켜보자.

다시 작업을 실행하고 결과로 출력된 JSON 파일을 열어보면 한글로 잘 출력된 것을 확인 할 수 있다. 그리고 실제 사이트와 데이터를 비교해 보면 다음과 같이 잘 수집되었음을 확인 할 수 있을 것이다.

실제 사이트와 JSON 결과 파일 비교

데이터 수집 결과 까지 확인했으니 이제 남은 것은 주기적으로 실행되도록 하는 것인데, CRON Job을 사용하면 쉽게 Scheduling을 할 수 있다.

그런데… CRON은 무엇이 길래 Scheduling을 해준다는 것일까?

CRON이란, Unix system OS의 시간기반 Job scheduler다. 고정된 시간, 날짜, 간격에 맞춰 주기적으로 실행 할 수 있도록 scheduling을 할 수 있게 해주는데 여기에 수행할 Job(작업)을 지정해 주면 scheduling된 시점에 주기적으로 Job이 실행 되는 것이다.
(좀 더 자세한 CRON에 대한 설명을 원한다면, WiKi를 참고하길 바란다.)

CRON

CRON Job이 어떤 것인지 알아보았으니 만들어 사용해 보자.

먼저, Job으로 실행될 bash script file(crawl.sh)을 아래와 같이 만들어 준다.

#!/bin/sh
# spider project가 있는 프로젝트로 이동
cd newsCrawler/spiders

# scrapy가 설치된 python의 가상환경에서 spider 실행
pipenv run scrapy crawl newsBot -o ./newsCrawler/json/result.json

그 다음 만든 Script를 아래와 같이 CRON에 추가해 주면 Crawler에 대한 Scheduling 작업이 완료된다.

# 매일 0시 0분에 Crawling 작업을 한다.
0 0 * * * /Users/Python/newsCrawler/crawl.sh

정상적으로 CRON에 등록 되었다면 매일 0시 0분에 Cralwer가 동작 할 것이고 실행 결과는 json 폴더에 업데이트 될 것이다.

참고로, CRON Job이 정상적으로 동작했다면 아래와 같은 Syslog를 확인 할 수 있다.

Dec 14 00:00:00 DESKTOP CRON[1327]: (root) CMD (/Users/Python/newsCrawler/crawl.sh)

여기까지 Scrapy 오픈소스 라이브러리를 사용하여 Web Crawling 작업을 해 보았다.

간단히 사용법을 알아보는 정도에서 구성한 것이라 좀더 자세한 설명이나 추가적인 설명이 필요하다면, Scrapy에 대한 정보는 공식문서를 참고하길 바란다.

Web Crawling with Scrapy(1)

인터넷 상에는 무수히 많은 데이터가 있다. 그리고 우리는 그것을 수집하여 활용하고 싶지만 쉽지가 않다.

예를 들어 최근 뉴스를 수집하여 트랜드를 분석한다고 한다면, 뉴스 데이터를 어디서, 어떻게 얻을 것인가?

이미 잘 정리해서 제공하는 곳이 있다면 참 좋겠지만, 현실적으로 내가 원하는 데이터가 딱맞춰 제공되는 경우는 없다고 보는게 맞다. 그렇다면 원하는 데이터를 직접 수집을 해야한다는 말인데… 어떻게 할 수 있을까?

가장 단순하게는 인터넷 포털 사이트에서 하나하나 검색해서 수집할 수도 있지만, 수집에만 들어가는 시간과 노력이 만만치 않게 들어갈 것이다.

이런 데이터 수집에 대한 어려움을 프로그래밍으로 해결할 수 있다. 그 방법은 바로 Crawling(혹은 Scraping)이란 것이다.

Crawling을 하기위한 방법들은 여러가지가 있지만, 여기서는 Python 오픈소스 라이브러리 제공되고 쉽게 사용할 수 있는 Scrapy를 사용하여 Web Crawling을 하는 방법에 대해서 알아 보겠다.

Scrapy 라이브러리를 사용하기 위해서 다음과 같이 Scrpay 패키지를 설치해야 한다.

$ pip install scrapy

설치가 완료되면 Scrapy에서 제공하는 Shell을 이용할 수 가 있다. Shell에서는 간단히 명령문으로 만으로도 쉽게 Crawling을 실행 해 볼 수 있는데, 본격적으로 Crawling 프로그래밍을 하기 전에 수집할 데이터에 대한 이해를 하기 위해서 먼저 탐색적 접근을 해 볼 수 있다는 장점이 있다.

그럼, Shell을 이용하여 데이터를 탐색하고 수집해 보겠다.

# Scrapy Shell 실행
$ scrapy shell

Shell이 실행 되었으면, 데이터 수집을 시작 할 웹 사이트 위치를 지정해 준다.

# Daum 랭킹뉴스 - 많이 본 뉴스
$ fetch('https://news.daum.net/ranking/popular')
2020-12-08 00:10:23 [scrapy.core.engine] INFO: Spider opened
2020-12-08 00:10:23 [scrapy.core.engine] DEBUG: Crawled (200)  (referer: None)

정상적으로 실행 됬다면, Crawled라는 메시지와 함께 Response Code가 200으로 떨어지는 것을 확인 할 수 있다.

Crawler가 받은 데이터는 로컬 임시폴더(%userprofile%/AppData/Local/Temp)에 저장되어 지는데 다음과 같이 보기 명령문을 통해 데이터를 확인해 볼 수 있다.

$ view(response)

위 보기 명령문이 실행되면, HTML 페이지가 브라우저로 열릴 것이다. 그리고 해당 HTML 페이지는 실제 사이트가 아닌 로컬주소로 나타나는 것을 확인 할 수 있다. 이를 통해서 Scrapy가 웹 사이트를 Crawling하여 수집한 데이터는 HTML 페이지라는 것을 알 수 있다. 그리고 이 HTML 페이지 중에서 필요한 데이터 위치를 찾아서 추출 및 가공을 하여 유용한 데이터로 만들어 내면 되는 것이다.

그런데… HTML 페이지에서 어떻게 필요한 데이터 위치를 찾을까?

대부분의 HTML 페이지는 일종의 Document라고 할 수 있다. 그리고 Document는 DOM(Document Object Model)형태로 표현된다. 때문에 DOM을 활용하면 필요한 데이터 위치를 추적할 수 있다.

여기서 수집 하려고 하는 데이터는 다음과 같다고 정의해 보자.

  1. 제목
  2. 출처
  3. 미리보기(이미지, 글)

브라우저의 개발자 도구(F12)를 실행시켜 DOM 구조를 살펴보자.

DOM 구조와 데이터 위치

모든 뉴스는 “list_news2”라는 클래스를 속성 값으로 가진 UL Tag안에 모여 있는 것을 확인 할 수 있다. 그리고 각 수집 할 데이터 들은 그 하위 LI Tag 안에 위의 색으로 표시해둔대로 위치해 있는 것을 알 수 있다.

이제, 알아낸 데이터 위치 정보를 XPath 함수에 입력하여 필요한 데이터를 수집하면 된다.

첫 번째 수집 대상인 뉴스 기사 제목 부터 수집해 보자. XPath에 뉴스 제목의 위치 정보를 넘기기 위해서 다음과 같이 표현 할 수 있다.

'//ul[@class="list_news2"]/li/div[2]/strong/a/text()'

이 것의 의미는 “UL Tag 중에서 list_news2라는 클래스 속성 값을 갖는 객체를 Root로 한다. Root 밑에 개별 기사는 LI Tag에 담겨 있고, 그 밑에 두 번째 DIV 밑에 STRONG 밑에 A Tag Text에 기사 제목이 있다.” 라는 것이다.

위 표현 값을 XPath 함수에 넣어 실행해 보자.

# 뉴스 기사 제목
$ response.xpath('//ul[@class="list_news2"]/li/div[2]/strong/a/text()').extract()

실행 결과로 50개의 모든 뉴스 기사 제목을 리스트 형태로 반환한 것을 확인 할 수 있다.

['[날씨] 겨울 한파 찾아온다..9일 밤부터 곳곳 눈·비',
  '잘린 손가락 들고 20개 병원 전전 "코로나 아니면 치료도 못 받나요"',
  '"문 대통령 취임 초기 기대 컸지만.. 지금은 아니다"',
  "오보라던 '그들의 술자리'..총장도 검사들도 '조용'",
  '소형 오피스텔까지 싹쓸이.."막을 방법 없다"',
  .... 생략 ....
]

같은 방법으로 나머지 데이터도 수집해 보자.

# 뉴스 출처(언론사)
$ response.xpath('//ul[@class="list_news2"]/li/div[2]/strong/span/text()').extract()

# 미리 보기 글
$ response.xpath('//ul[@class="list_news2"]/li/div[2]/div[1]/span/text()').extract()

# 미리 보기 이미지 주소
$ response.xpath('//ul[@class="list_news2"]/li/a/img/@src').extract()

여기까지 잘 실행이 되었다면, Shell를 통해서 수집하려고한 대상 데이터에 대해서 Crawling이 가능하다는 것을 확인한 샘이다.

Shell 명령 코드로 수행해본 Crawling 작업이 1회성으로 데이터를 수집하고 끝나는 것이 라면 이대로 끝내면 되겠지만, 데이터를 주기적으로 추가 수집하거나 업데이트가 필요하다면, 매번 Shell 명령코드로 수행하기 어려울 것이다.

이런 부분은 Shell 명령 코드를 Crawler 모듈로 만들어서 주기적으로 실행 할 수 있으면 좋을 것이다.

다음 포스트에서는 이번 포스트에서 사용한 Shell 명령 코드를 그대로 활용하여 Spider Project를 만들고 주기적으로 데이터를 업데이트 할 수 있는 Crawler를 만들어 보겠다.

인공지능 프로그램 이해와 비즈니스 적용에 관하여

최근 인공지능이 실제 비즈니스에 적용되면서 많은 산업의 전반에 영향을 미치고 있다.
Statista에 따르면 세계적으로 인공지능에 대한 시장 전망이 2018년 약 95억달러에서 연 평균 43%씩 성장하여 2025년에는 1,186억달러 규모로 이를 것이라고 한다.

Revenues from the artificial intelligence (AI) software market worldwide from 2018 to 2025

AI를 포함한 글로벌 소프트웨어 서비스 전체 시장이 2018년부터 2025년까지 매년 10% 성장하여 3,229억 달러 규모가 될 것이라는 것을 생각해 보면 엄청난 투자와 성장이 이루어지고있다는 것을 알 수 있다.

이런 이유로 사업을 하는 사람이라면 누구나 기업 비즈니스에 어떻게든 하루 빨리 인공지능을 도입하고 싶을 것이다.

“그런데 정말 인공지능을 도입하면 비즈니스의 매출이 성공적으로 올라갈까?”
“기존의 소프트웨어 프로그램들로는 할 수 없는 것인가?”

이것에 대해 이야기하기 전에 먼저 기존의 소프트웨어 프로그램들이 어떠했는지 생각해 볼 필요가 있다.

그 동안의 프로그램들은 연속적이지 않고 구분되어진 이산 논리를 가지고 나오는 경우 수들을 공식화하여 만든 것들이다.

우리의 일상생활을 살펴 보자.

아침에 일어나야 하기 때문에 매일 아침 7시가 되면 알람이 울리도록 알람을 맞춘다. 시간은 사실 연속적이지만 그 시간을 시, 분, 초로 이산화 시켜 표기하고 아침 7시라는 경우가 되면 알림이 울리도록 되어 있는 것이다.

이것 저것 분주히 준비한 다음 집을 나서면 엘리베이터를 마주하게 된다. 엘리베이터의 한쪽 벽에 표시된 층수를 누르면 엘리베이터는 해당 층수로 이동한다. 공간 또한 마찬가지로 연속적이지만 층이라는 규격화된 높이로 이산화 시켜 표시하고 눌려진 버튼에 입력된 층의 위치로 이동하는 것이다.

예시에서 알 수 있듯이 이산 논리는 확실하게 구분된다. 어떤 경우에 해당되는지 그렇지 않은 것인지 확실한 선을 긋는 것이다. 이 선들이 조건(Rule)이 되고 조건들을 조합하여 공식을 만든 것이 프로그램이 되는 것이다.

일상에서 쉽게 볼 수 있는 간단한 프로그램들을 예시로 들었지만 사업에 사용되는 프로그램들도 마찬가지다. 단지, 관련 분야의 도메인 전문가가 문제를 해결하기 위해서 좀 더 세분화된 조건(Rule)들을 도출해 냈을 뿐이다.

예를 들어, 어느 과수원에서는 사과를 중량으로만 선별 하고 중량을 나누는 작업을 자동화 시스템으로 개발 한다고 가정해 보자. 먼저, 각 사과들의 중량을 측정할 것이다. 그리고 측정된 중량들을 이산화 된 등급의 조건으로 만들어 준다. 가령 200~350g이면 가정용, 351~400g이면 선물용 , 401g 이상은 제수용으로 등급을 만들어 주면 이 시스템을 통해서 사과들은 3개의 등급으로 구분되게 된다.

이 시스템에서는 사과의 무게가 350g이라면 가정용으로 분류할 것이다. 그리고 351g은 선물용으로 분류가 될 것이다. 그러면 1g 차이로 가정용과 선물용으로 분류 되는데 이 것이 합리적인 것일까? 350g이 351g보다 실제로 선물용으로 가치가 더 있다면?

실제로 사과를 제대로 선별하기 위해서는 중량 외에 빛깔, 형상, 과육 등등 기준들이 더 많이 있어야 한다. 때문에 사과를 좀 더 잘 선별하기 위해서는 ‘사과’라는 여러 속성을 갖는 객체를 만들고 각 속성에 값을 측정하여 입력하고 특정 조건이 만족할 경우 분류 되게 해야 한다.

그럼 다시 질문해 보자. 전 보다 조건이 많아 졌으니 이제는 합리적으로 나눌 수 있는 것일까?

글쎄다. 어디까지나 이산 논리에 대한 조건들이 세분화 된 것일 뿐이지 경계가 불분명한 예외사항은 언제나 발생 하고, 발생한 예외는 결국 사람이 처리해야 한다. 이것이 인공지능 이전의 프로그램 방식들인 것이다.

“그렇다면, 인공지능이 도입된 프로그램 방식은 무엇 일까?”

1(참)과 0(거짓)으로만 나누는 이산적인 방식에서 0~1 사이의 모든 실수로 확장된 것을 의미한다. 다시 말하면 어떤 등급에 속할 가능성으로 나타내는 것이다.

예를 들어, 사과의 중량은 350g이지만 다른 조건들로 인해 이 사과가 선물용으로 적합하다는 가능성이 0.86으로 정의 할 수 있다면 이 사과는 가정용이 아니라 선물용이 되는 것이다. 이처럼 경계선이 명확하지 않은 대상을 다룰 수 있는 것이 인공지능이 도입된 프로그램 방식이다.

이렇게 간단하게 설명하면 신기하게 들릴 수도 있지만 이것은 그 동안 잘 처리하지 못한 불분명한 예외사항을 기계가 효율적으로 나누기 위한 추론 기법일 뿐이다.

사람은 350~351g의 애매한 중량의 사과라면 손으로 만져보고 눈으로 보고 향을 맡아본 뒤 직관적으로 분류했을 것이다. 이렇게 사람이 분류 하던 데이터들을 기계에게 학습시키면, 기계는 데이터에서 패턴을 찾고 그 패턴을 추론로직으로 사용하는 것이다.

결국, 완전한 인공지능이라기 보단 사람의 직관을 흉내낼 수 있어서 사람의 인지적인 부분을 도와 줄 수 있는 형태인 것이다.

그런데 왜 이렇게 사람들이 관심을 갖고 열광하는 것일까?

그 이유는 최근 몇 년 사이 그 흉내내는 수준이 단순 흉내 이상의 가치를 만들고 시작했기 때문이다. 가장 가깝게는 스마트 폰으로 사진을 찍으면 사진을 자동으로 보정하고 분류해준다. 공장에서는 제품의 상태를 사람 보다 더 잘 예측하고, 병원에서는 환자의 영상데이터를 의사보다 더 정확히 분석하고 있다.

인지능력으로는 이미 인간의 수준을 넘어선 것있다.

이런 기능이 물리적인 제약 없이 24시간 365일 쉬지 않고 동작 할 수 있기 때문에 완전한 인공지능이 아님에도 불구하고 비즈니스 매출에 성공적인 상승 가져다 주는 것이다.

“그렇다면, 어떻게 하면 인공지능을 비즈니스에 적용 할 수 있을까?”

인공지능을 비즈니스에 적용하기 위해서는 많은 것들이 필요하지만 꼭 필요한 3가지가 있다.

첫째로 비즈니스에서 해결하고자 하는 문제점을 정확히 알아야 한다.
위에서 설명했듯이 최근의 인공지능은 완전한 인공지능이 아니기 때문에 그저 ‘도입하면 무엇이든 되겠지’라고 생각 하는 순간 실패사례로 남게 된다. 문제점을 잘 파악하기 위해서 비즈니스에 대한 프로세스를 잘 정립하고 프로세스 간의 절차와 관계를 정의하여 해결하려고 하는 문제점을 정확히 이해하고 도출해야 한다.

두번째로, 인공지능이 학습 가능한 데이터로 기존 데이터를 가공하고 수집해야 한다.
인공지능에 대한 환상으로 인해 생긴 오해 중 하나인데, 무작정 데이터가 있다고 해서 바로 인공지능에게 데이터를 학습시킬 수 있는 것이 아니다. 데이터에는 생각지도 못한 많은 노이즈 정보들이 있으며, 현재의 인공지능은 이런 정보까지 분별하지 못 한다. 특히, 데이터가 비정형 데이터라면 전처리 기술을 통해서 정형화 혹은 반정형화 작업을 해주어야 학습에 사용할 수 있다. 때문에 인공지능이 학습 가능한 형태로 데이터를 새롭게 만들어 가야 한다.

마지막으로 오픈소스 소프트웨어를 잘 활용해야 한다.
일반 기업에서 인공지능을 처음부터 개발한다는 것은 불가능에 가깝고, 투자가 가능하더라도 너무 뒤쳐지는 발상이다. 이미 잘 개발된 인공지능에 관련한 오픈소스들이 너무 많다. 국내 최고 기술 회사인 삼성, LG는 물론이고 글로벌 선두 IT 기업인 AMG(Amazon, MS, Google)도 인공지능 만큼은 오픈소스를 활용한다.
우리는 거인의 어깨에 올라탈 필요가 있다. 이미 글로벌 기업들이 자신들의 비즈니스로 검증한 오픈소스를 이용하는 것이 비용을 아끼면서 빠르게 성장할 수 있는 발판이 되는 것이다. 오픈소스에 기존 비즈니스를 잘 녹여낼 수 있다면 손쉽게 인공지능 서비스를 제공할 수 있음과 동시에 글로벌 기업의 인공지능 기술을 같이 공유하게 되는 것이다.

그 동안 공상과학 영화에서나 나오던 인공지능에 대한 것들이 점점 현실로 다가 오고 있다. 아직 사회적 부작용도 많고 완성도에서도 완전한 인공지능은 아니지만 인공지능 시장의 성장와 규제 대응 속도를 가만해 보면 향후 5~10년 안에는 우리 생활 속에 정착할 것으로 보인다. 그 때에 앞서가는 비즈니스를 하고 있으려면, 기존 비즈니스를 인공지능을 통해서 어떤 새로운 가치를 만들어 낼 것인가를 고민하는 것이 중요할 것 같다.

About Raspbian

Raspbian은 하드웨어 제품인 RPi(Raspberry Pi)와 Linux계열의 OS(Operating System)인 Debian의 합성어로 Raspberry Pi Foundation이 개발한 RPi 전용 OS다.

RPi는 Raspberry Pi Foundation에서 학교와 개발도상국에서 기초 컴퓨터 과학의 교육을 증진시키기 위해 개발한 신용카드 크기의 싱글 보드 컴퓨터이다.
크기가 작고 전력 소비가 5V-2A로 동작하도록 설계되어 있기 때문에 Raspbian은 저전력 ARM CPU에 상당히 최적화되 도록 만들어 졌다.

Raspberry Pi 4 board

Raspbian을 사용하기 위해서는 앞서 설명한 RPi라는 하드웨어가 필요하다.

(Desktop 버전을 사용하여 live Disc를 생성하거나, 가상머신을 이용하여 PC에 설치 할 수도 있다.)

RPi Model B+RPi 2 Model BRPi 3 Model BRPi 4 Model B
SoCBCM2835BCM2836BCM2837BCM2711
CPUARM11 @700MHzQuad Cortex
A7@900MHz
Quad Cortex
A53@1.2Ghz
Quad Cortex
A72@1.5Ghz
Instruction SetARMv6ARMv7-AARMv8-AARMv8-A
GPU250MHz VideoCore IV250MHz VideoCore IV400MHz VideoCore IV500MHz VideoCore VI
RAM512MB SDRAM1GB SDRAM1GB SDRAM1, 2 or 4 GB
WirelessNoneNone802.11n/Bluetooth 4.0802.11n/Bluetooth 5.0
VideoHDMI/CompositeHDMI/CompositeHDMI/Composite2x micro-HDMI/Composite
AudioHDMI/HeadphoneHDMI/HeadphoneHDMI/HeadphoneHDMI/Headphone
RPi는 그래픽 성능을 띄어나지만 매우 저렴한 가격(약 25~35$)에 구입할 수 있다.

RPi는 OSHW(Open Source Hardware)라서 하드웨어 스팩은 물론이고 전용 OS인 Raspbian역시 오픈소스로 공개 되어 있기 때문에 하드웨어만 구입하면 나머지 사용하는 것에 대해서는 100% 무료로 사용할 수 있다.

RPi 전용 OS인 Rapbian은 Debian을 기반으로 만들어 졌기 때문에 대부분의 주요 명령어는 Debian과 거의 동일하게 사용하는 하다.

  • APT(Advanced Package Tool)을 통한 소프트웨어 설치 / 업데이트
  • dpkg(Debian package) 형식의 패키지 소프트웨어 사용

PIXEL(Pi Improved Xwindows Environment, Lightweight)이라는 GUI 기능 제공을 한다. 이를 통해서 데스크탑 환경을 사용할 수 있다. 특히, 데스크탑 환경 중 App Store와 동일한 개념의 PI Store 제공하여 호환되는 Package들을 쉽게 제공 받을 수 있도록 되어 있다.

Raspbian Pi Store

오픈소스 싱글 보드계열 중에서 저렴하고 파워풀한 기능을 제공하고 있어서 가성비가 좋은 제품으로 많은 개발자들에게 사랑 받고 있다.

전 세계적으로 많은 개발자들이 사용하고 있다 보니 많은 관련 개발 커뮤니티들도 분야별로 자연스럽게 형성되고 있다. 초급자라면 관심 있는 분야의 커뮤니티에서 많은 정보(Tip)들을 제공 받을 수 있다. (오픈소스의 장점이 잘 살려진 것 같다.)

커뮤니티 링크: https://www.raspberrypi.org/community/

Dependency Injection 개념과 Ninject 사용법

소프트웨어를 잘 만들기 위해서 많은 디자인 패턴들이 사용되는데, 그중에서 DI(Dependency Injection, 의존성 주입)에 대한 개념과 .NET MVC에서 많이 사용되는 DI Framework들 중 하나인 Ninject(Open Source Project)에 대해서 알아보겠다.

DI(Dependency Injection) 란?

프로그래밍에서 사용되는 객체들 사이의 의존관계를 소스코드가 아닌 외부 설정파일 등을 통해 정의하게 하는 디자인 패턴이다. 개발자는 각 객체의 의존관계를 일일이 소스코드에 작성할 필요 없이 설정파일에 의존관계가 필요하다는 정보만 된다. 그러면 객체들이 생성될때, 외부로부터 의존관계를 주입 받아 관계가 설정 된다.

DI를 적용하면, 의존관계 설정이 컴파일시 고정 되는 것이 아니라 실행시 설정파일을 통해 이루어져 모듈간의 결합도(Coupling)을 낮출 수 있다.
결합도가 낮아지면, 코드의 재사용성이 높아져서 모듈을 여러 곳에서 수정 없이 사용할 수 있게 되고, 모의 객체를 구성하기 쉬워지기 때문에 단위 테스트에 용이해 진다.

이제, .NET에서 MVC 프로젝트를 만들때 DI를 구현하기 위해 가장 많이 사용하는 Open Source인 Ninject에 대해서 알아보자.

NInject 알아보기

(공식 페이지 : http://www.ninject.org/)

간단히 이름부터 살펴보면, NInject는, N(Ninja) + Inject로 대표 이미지로도 Ninja로 되어 있다.

홈페이지 대문에 보면 “Be fast, be agile, be precise”라는 슬로건이 있는데 닌자처럼 빠르고 민첩하며 정확하게 프로그램을 만들수 있게 하겠다는 정신이 담겨있는 것 같다.

(Nate Kohari라는 소프트웨어 엔지니어가 최초 개발을 했는데, 개인적인 생각으로는 N을 중의적인 의미로 사용한게 아닌가 싶다. 참고 : https://www.infoq.com/articles/ninject10-released/)

NInject는 Open Source 라이브러리로 Apache License 2.0에 따라 배포되었으며,
2007년 부터 .NET 어플리케이션의 DI를 구현하기 쉽게 해주도록 지원하고 있다.

이제, 실제로 사용해 보자

NInject 사용해 보기

  1. Package Install
    • Visual Studio에서 제공하는 Nuget Package Installer를 사용하여 다음 Package들을 설치한다.
      – Ninject
      – Ninject.Web.WebApi
      – Ninject.Web.Common
      – Ninject.Web.Common.WebHost
  2. Edit Ninject.Web.Common.cs
    • 위 Package 설치가 완료되면, 프로젝트 최상단에서 App_Start 폴더에 Ninject.Web.Common.cs 파일이 생성된 것을 확인 할 수 있다.
    • 해당 파일을 열어 보면, CreateKernel이라는 method가 있는데 다음 코드를 추가한다. 그러면 NInject가 controller의 의존성 주입을 구성해 줄 수 있게 된다.
RegisterServices(kernel);
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;
  1. Register Service
    • 스크롤을 조금 내려 보면, RegisterServices라는 method를 확인 할 수 있는데, 실제로 의존관계를 설정(bind)하는 곳이다. 의존성을 주입할 객체들의 관계를 다음과 같이 추가한다.
private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<ICommonStore>().To<CommonStore>();
}
  1. Use it on controller
    • 이제 의존성 주입을 위한 IoC 설정과, 의존관계 설정(bind)작업을 모두 하였으니 Controller에서 사용해보자.
public class CommonStoreController : Controller
{    
    public CommonStoreController(ICommonStore common)
    {
        this.commonStore = common;
    }

    private ICommonStore commonStore;

    public int GetItemCount(string id)
    {
        return commonStore.Add(id);
    }
}

Design Pattern 중 DI(Dependency Injection, 의존성 주입)이라는 패턴에은 표준 프로그래밍을 할 때 중요한 요소이긴하지만 무조건 사용해야 하는 것은 아니다. 간단한 프로그램이나 객체간의 결합이 명확하여 구분하지 않아도 되는 경우 굳이 프로젝트를 무겁게(?) 만들 필요없다.

그리고 Ninject는 .NET에서 많이 사용되는 Open Source DI Framework 중 하나로 DI를 할 때 쉽게 구현할 수 있어서 선호되는 편이지만 다양한 DI Open Source Framework들이 있으며, 성능 면에서도 훨씬 더 좋은 것들이 있으니 확인하고 사용하길 바란다.
(참고 : https://www.claudiobernasconi.ch/2019/01/24/the-ultimate-list-of-net-dependency-injection-frameworks/)

Azure DevOps 개요

DevOps 란?

데브옵스(DevOps)는 소프트웨어의 개발(Development)과 운영(Operations)의 합성어로서, 소프트웨어 개발자와 정보기술 전문가 간의 소통, 협업 및 통합을 강조하는 개발 환경이나 문화를 말한다.

주로 아래 그림과 같이 개발과 운영간의 연속적인 사이클로 설명할 수 있다.

이를 통해서 얻는 장점은 다음과 같다.

  1. 신속한 제공
    • 릴리스의 빈도와 속도를 개선하여 제품을 더 빠르게 혁신하고 향상할 수 있다. 새로운 기능의 릴리스와 버그 수정 속도가 빨라질수록 고객의 요구에 더 빠르게 대응할 수 있다.
  2. 안정성
    • 최종 사용자에게 지속적으로 긍정적인 경험을 제공하는 한편 더욱 빠르게 안정적으로 제공할 수 있도록, 애플리케이션 업데이트와 인프라 변경의 품질을 보장할 수 있다.
  3. 협업 강화
    • 개발자와 운영 팀은 긴밀하게 협력하고, 많은 책임을 공유할 수 있도록, 워크플로를 결합한다. 이를 통해 비효율성을 줄이고 시간을 절약할 할 수 있다.
  4. 보안
    • 제어를 유지하고 규정을 준수하면서 신속하게 진행할 수 있다. 자동화된 규정 준수 정책, 세분화된 제어 및 구성 관리 기술을 사용할 수 있다.

그럼, DevOps를 실현하기 위해서는 어떻게 해야 하는가?

DevOps를 실현하기 위해서는 CI(Continuous Integration)/CD(Continuous Deployment(Delivery))라는 2가지 작업을 해야 한다.

CI(Continuous Integration)은 Development에 속하는 작업으로 지속적으로 프로젝트의 요구사항을 추적하며, 개발된 코드를 테스트 및 빌드를 수행한다.

  1. 프로젝트 기획 + 요구사항 추적
    • 프로젝트 시작
    • 기획(프로젝트 방법론 채택)
    • 작업관리(Backlog 관리)
    • 진행상황 추적
  2. 개발 + 테스트
    • 코드작성
    • 단위 테스트
    • 소스제어
    • 빌드
    • 빌드 확인

CD(Continuous Deployment(Delivery))는 Operations에 속하는 작업으로 CI가 완료되어 빌드된 소스를 통합 테스트(개발, QA, Staging)를 거쳐 배포를 하며, 배포된 사항들을 지속적으로 모니터링하고 프로젝트 요구사항에 피드백하는 작업을 수행한다.

  1. 빌드 + 배포
    • 자동화된 기능 테스트
    • 통합 테스트 환경(Dev)
    • 사전 제작 환경
      (QA, Load testing)
    • 스테이징 환경(Staging)
  2. 모니터링 + 피드백
    • 모니터링
    • 피드백

이제, DevOps를 하기위한 구체적인 작업을 알았으니, 실제 구성을 하도록 하는 제품들에 대해서 알아보자.

Azure DevOps vs Other Software

DevOps를 하기 위한 솔루션들은 이미 시중에 엄청나게 나와 있으며, 대게 오픈소스 형태로 많이 제공되고 있어서 바로 가져다 사용할 수 있다.

위 그림에서 볼 수 있듯이 DevOps의 각 단계에 맞추어서 원하는 (특화된)제품을 선택하여 사용하면 된다.

모든 단계를 빠짐 없이 구현한다고 가정하여, 예를 들면 다음과 같이 DevOps가 구현 될 수 있다.

  1. Slack으로 요구사항 관리를 하고
  2. Git으로 소스코드 관리를 하고
  3. Maven으로 빌드를 하고
  4. JUnit으로 테스트하고
  5. Jenkins로 Docker에 배포하고
  6. Kubernetes로 운영하며
  7. Splunk로 모니터링 한다.

그런데 이런 경우, 벌써 필요한 제품에 8개나 된다. 프로젝트에 참여하는 모든인원이 이 제품들에 대해서 이해하고 사용하기 어려우며, 각 제품에대한 담당자들있어야 제대로 운영 될 수 있을 것이다. 게다가, 각기 다른 제품이라 다음 단계로 넘어가기 위한 추가적인 관리를 해야할 것이다.

이렇게 되면, 규모가 작은 곳에서는 몇가지 단계를 건너띄고 관리를 하게 되는데 이런 부분에서 예외사항이 생기기 시작하고, 결국 프로젝트 끝에서는 DevOps를 거의하지 못하는 상황이 생길 수 도있다.

반면, Azure DevOps는 하나의 DevOps 관리 솔루션을 제공한다. 때문에 Azure DevOps 하나만 사용해도 모든 절차를 구성 할 수 있다.
그리고 만약, 기존에 사용하던 제품이 있다 하더라도 아래 그림과 같이 3rd-party를 마이그레이션 혹은 연동 설정 할 수 있도록 하기 때문에 Azure DevOps 제품안에서 하나로 통합 관리 할 수 있다.

마지막으로, Azure DevOps를 사용하는 간단한 시나리오에 대해서 알아보자.

Azure DevOps에서는 파이프라인이라는 형태로 CI/CD를 구성하도록 되어 있으며, 각 단계 구성은 아래 그림과 같다.

  1. Project (Agile) Board를 통해서 프로젝트 요구사항 추적 관리를 하고
  2. Repo에서 각 Agile Board Task에 대한 소스코드 관리를 하고
  3. 소스가 커밋이 되면 CI 파이프라인을 통해 빌드 + 테스트를 수행하고
  4. CI가 완료되면 Trigger 형태로 CD 파이프라인을 실행하고
  5. CD 파이프라인을 통해 통합 테스트 + 배포를 하고
  6. (옵션)담당자에게 최종 승인을 받고
  7. 운영 적용 및 모니터링을 한다.

Azure DevOps 이 외의 제품을 사용 했을 때와 단계는 거의 동일 하지만, 여기서 주목 할 점은 Azure DevOps 단일 제품에서 모두 제공 받고 구성 할 수 있다는 것이다.

(**여기서 다 설명 못한 부분이지만 CI/CD 과정 중에 Function(Trigger) 형태로 여러 기능들을 다양하게 엮을 수도 있다. 예를 들어 6번)

각각의 솔루션 전문가들이 있어서 운영한다면 문제가 없겠지만, DevOps를 처음 도입한다던가 규모가 작아 축소 운영을 해야하는 상황이라면 고려해 볼 수 있을 것 같다.