30๋ถ„ ์•ˆ์— ์›น ์„œ๋น„์Šค๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๋ด‡: ํ…”๋ ˆ๊ทธ๋žจ + bash + cron

30๋ถ„ ์•ˆ์— ์›น ์„œ๋น„์Šค๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๋ด‡: ํ…”๋ ˆ๊ทธ๋žจ + bash + cron

์ƒˆ๋กœ์šด ์„œ๋น„์Šค์— ๋Œ€ํ•œ ๋ชจ๋‹ˆํ„ฐ๋ง์„ ์‹ ์†ํ•˜๊ฒŒ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜์ง€๋งŒ, ๊ธฐ์„ฑ ์ธํ”„๋ผ๋‚˜ ์ „๋ฌธ ์ง€์‹์ด ๋ถ€์กฑํ•œ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฐ€์ด๋“œ์—์„œ๋Š” bash, cron, curl๊ณผ ๊ฐ™์€ Ubuntu ๋‚ด์žฅ ๋„๊ตฌ๋งŒ์„ ์‚ฌ์šฉํ•˜์—ฌ 30๋ถ„ ์•ˆ์— ๋ชจ๋“  ์›น ์„œ๋น„์Šค๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๋„๊ตฌ๋ฅผ ๊ตฌํ˜„ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์•Œ๋ฆผ ์ „๋‹ฌ์—๋Š” Telegram์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

"ํ™”๋ คํ•œ ์žฅ์‹"์€ ์‚ฌ์šฉ์ž์˜ ๊ฐ์ •์  ์ฐธ์—ฌ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ ์‚ฌ์šฉ์ž๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ…Œ์ŠคํŠธํ•œ ๊ฒฐ๊ณผ, ํšจ๊ณผ๊ฐ€ ์žˆ๋Š” ๊ฒƒ์œผ๋กœ ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค.

์›๊ฒฉ ์ง„๋ฃŒ ์„œ๋น„์Šค์ธ Doctor Nearby์—์„œ ์‚ฌ์šฉ์ž์˜ ์ŠคํŠธ๋ ˆ์Šค ์ˆ˜์ค€์„ ํŒŒ์•…ํ•˜๊ธฐ ์œ„ํ•œ ์ฑ—๋ด‡์„ ๊ฐœ๋ฐœํ•  ๋•Œ, ๋ชจ๋‹ˆํ„ฐ๋ง์ด ํ•„์š”ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ช‡ ์‹œ๊ฐ„ ๋งŒ์— ํ›Œ๋ฅญํ•˜๊ฒŒ ์ž‘๋™ํ•  ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๊ธ์ •์ ์ธ ๋ฉ”์‹œ์ง€๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฏธ๋‹ˆ ํ”„๋กœ์ ํŠธ๊ฐ€ ํƒ„์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

๋จผ์ €, ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์žˆ๋Š” ์ €์žฅ์†Œ๋ฅผ ๊ฐ€์ ธ์˜ค๊ฒ ์Šต๋‹ˆ๋‹ค.

git clone https://github.com/rshekhovtsov/msms.git

msms ํด๋”๋กœ ๊ฐ€์„œ ์ž‘์—…์„ ๊ณ„์†ํ•ฉ๋‹ˆ๋‹ค.

ํ…”๋ ˆ๊ทธ๋žจ์ด ์ฐจ๋‹จ๋œ ๊ฒฝ์šฐ ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. ๊ฐ€์žฅ ์‰ฝ๊ณ  ์•ˆ์ •์ ์ธ ๋ฐฉ๋ฒ•์€ torsocks์ž…๋‹ˆ๋‹ค.

sudo apt install tor
sudo apt install torsocks

์˜ˆ๋ฅผ ๋“ค์–ด, google.com ํ™ˆํŽ˜์ด์ง€ ๋ชจ๋‹ˆํ„ฐ๋ง์„ 3๋‹จ๊ณ„๋กœ ์„ค์ •ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

1๋‹จ๊ณ„. ํ…”๋ ˆ๊ทธ๋žจ์—์„œ ๋ด‡์„ ์ƒ์„ฑํ•˜๊ณ  ์‚ฌ์šฉ์ž ID๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค.

  • ํ…”๋ ˆ๊ทธ๋žจ ์—ฐ๋ฝ์ฒ˜ ๊ฒ€์ƒ‰์ฐฝ์—์„œ ๋‹ค์Œ์„ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค. @botfather:

    30๋ถ„ ์•ˆ์— ์›น ์„œ๋น„์Šค๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๋ด‡: ํ…”๋ ˆ๊ทธ๋žจ + bash + cron

  • ์‹œ์ž‘ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ์‹คํ–‰ํ•˜๊ณ , /newbot ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•œ ํ›„ ์งˆ๋ฌธ์— ๋‹ตํ•ฉ๋‹ˆ๋‹ค. name์€ ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘œ์‹œ๋˜๋Š” ๋ด‡์˜ ์ด๋ฆ„์ด๋ฉฐ, username์€ ๊ณ ์œ ํ•ด์•ผ ํ•˜๋ฉฐ "bot"์œผ๋กœ ๋๋‚˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    30๋ถ„ ์•ˆ์— ์›น ์„œ๋น„์Šค๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๋ด‡: ํ…”๋ ˆ๊ทธ๋žจ + bash + cron

    ๋ด‡์€ HTTP API์— ๋Œ€ํ•œ ๋น„๋ฐ€ ํ† ํฐ์„ ๋ฐœํ–‰ํ•˜๋Š”๋ฐ, ์ด ํ† ํฐ์€ msms ํด๋”์˜ telegram-api-key.txt ํŒŒ์ผ์— ๋ณต์‚ฌํ•˜์—ฌ ์ €์žฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • ํ…”๋ ˆ๊ทธ๋žจ ๊ฒ€์ƒ‰์ฐฝ์— ๋ด‡์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜๊ณ  ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • ๋งˆ์ง€๋ง‰์œผ๋กœ, ๋ชจ๋‹ˆํ„ฐ๋ง ์•Œ๋ฆผ ์ˆ˜์‹ ์ž ๋ชฉ๋ก์— ์šฐ๋ฆฌ ์ž์‹ ์„ ์ถ”๊ฐ€ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
    sudo chmod +x ./recipients-setup.sh
    torsocks ./recipients-setup.sh

    ์Šคํฌ๋ฆฝํŠธ๋Š” ๋ด‡์— ๋Œ€ํ•œ ์ตœ์‹  ์š”์ฒญ ๋ชฉ๋ก์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ํ…”๋ ˆ๊ทธ๋žจ์—์„œ ID์™€ ์ด๋ฆ„์„ ํ•œ ์ค„๋กœ ์ž…๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ID๋ฅผ services/google-recipients.txt ํŒŒ์ผ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์ผ ํ˜•์‹: ๊ฐ ์ค„์€ ํ•˜๋‚˜์˜ ID์ž…๋‹ˆ๋‹ค. ์˜ˆ:

    123456789
    987654321

์ƒˆ๋กœ์šด ์ˆ˜์‹ ์ž๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด Telegram์—์„œ ๋ด‡์„ ์‹œ์ž‘ํ•˜๋„๋ก ์š”์ฒญํ•˜๊ณ , receivers-setup.sh๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ํŒŒ์ผ์— ID๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

2๋‹จ๊ณ„. ๋ชจ๋‹ˆํ„ฐ๋ง ์„ค์ •

์„œ๋น„์Šค ์„ค๋ช…์€ services ํด๋”์— ini ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜์—ฌ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ๋‹ค์„ฏ ๊ฐ€์ง€ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  1. MSMS_SERVICE_NAME: ์„œ๋น„์Šค ์ด๋ฆ„ - ์•Œ๋ฆผ ๋ฐ ๋ชจ๋‹ˆํ„ฐ๋ง ๋กœ๊ทธ์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  2. MSMS_SERVICE_ENDPOINT: curl์„ ์‚ฌ์šฉํ•˜์—ฌ ์ ‘๊ทผํ•  ์„œ๋น„์Šค์˜ ์—”๋“œํฌ์ธํŠธ์ž…๋‹ˆ๋‹ค.
  3. MSMS_CURL_PARAMS: ์ถ”๊ฐ€ ์ปฌ ์˜ต์…˜์€ ์•„๋ž˜ ์˜ˆ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.
  4. MSMS_์˜ˆ์ƒ: ์„œ๋น„์Šค์—์„œ ์˜ˆ์ƒ๋˜๋Š” ์‘๋‹ต์ž…๋‹ˆ๋‹ค. ์‘๋‹ต์ด ์งง์„ ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  5. MSMS_์˜ˆ์ƒ_ํŒŒ์ผ: ์˜ˆ์ƒ ์„œ๋น„์Šค ์‘๋‹ต์ด ํฌํ•จ๋œ ํŒŒ์ผ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค. ์ด ๊ฐ’์„ ์ง€์ •ํ•˜๋ฉด MSMS_EXPECTED๋ณด๋‹ค ์šฐ์„ ํ•ฉ๋‹ˆ๋‹ค.
  6. MSMS ์ˆ˜์‹ ์ž: ์•Œ๋ฆผ ์ˆ˜์‹ ์ž ๋ชฉ๋ก์ด ํฌํ•จ๋œ ํŒŒ์ผ์ž…๋‹ˆ๋‹ค.

google.com์— ๋Œ€ํ•œ ์š”์ฒญ์€ ๋ฆฌ๋””๋ ‰์…˜๊ณผ ํ•จ๊ป˜ ๊ณ ์ •๋œ HTML์„ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ์ด๋ฅผ ์˜ˆ์ƒ ์„œ๋ฒ„ ์‘๋‹ต์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

curl google.com > services/google-response.html

services/google.ini ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

MSMS_SERVICE_NAME='google front page'

# service endpoint
MSMS_SERVICE_ENDPOINT='google.com'

# curl parameters
MSMS_CURL_PARAMS='-s --connect-timeout 3 -m 7'

# expected service response
MSMS_EXPECTED_FILE='google-response.html'

# recipients list file
MSMS_RECIPIENTS='google-recipients.txt'

ะ’ MSMS_CURL_PARAMS ๋‹ค์Œ์„ ํฌํ•จํ•˜์—ฌ curl์ด ํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ์ฝ˜์†”๊ณผ ๋กœ๊ทธ๊ฐ€ ๋ณต์žกํ•ด์ง€๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋ ค๋ฉด curl ๋ฉ”์‹œ์ง€๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜์„ธ์š”. -s
  2. ํ…Œ์ŠคํŠธ ์ค‘์ธ ์„œ๋น„์Šค์— ๋Œ€ํ•œ ์—ฐ๊ฒฐ ์‹œ๊ฐ„ ์ดˆ๊ณผ๋ฅผ ์ดˆ ๋‹จ์œ„๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. --connect-timeout 3
  3. ์‘๋‹ต์„ ๋ฐ›๊ธฐ ์œ„ํ•œ ์‹œ๊ฐ„ ์ดˆ๊ณผ๋ฅผ ์„ค์ •ํ•˜์„ธ์š”: -m 7
  4. SSL์— ๋Œ€ํ•œ ์ธ์ฆ์„œ ๊ฒ€์ฆ์„ ๋น„ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: ์ž์ฒด ์„œ๋ช… ์ธ์ฆ์„œ๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ): --insecure
  5. http ์š”์ฒญ ์œ ํ˜•์„ ์ง€์ •ํ•˜์„ธ์š”: -X POST
  6. ์ œ๋ชฉ์„ ์ง€์ •ํ•˜์„ธ์š”: -H "Content-Type: application/json"
  7. ์š”์ฒญ ๋ณธ๋ฌธ์„ ๋ฌธ์ž์—ด์ด๋‚˜ ํŒŒ์ผ๋กœ ์ง€์ •ํ•˜์„ธ์š”. ํŒŒ์ผ ํ˜•์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. -d @request.json

์•Œ๋ฆผ์„ ๋น„ํ™œ์„ฑํ™”ํ•˜๊ณ  ์—ฐ๊ฒฐ์— ๋Œ€ํ•œ ์‹œ๊ฐ„ ์ดˆ๊ณผ๋ฅผ 3์ดˆ, ์„œ๋น„์Šค๋กœ๋ถ€ํ„ฐ ์‘๋‹ต์„ ๋ฐ›๋Š” ๋ฐ 7์ดˆ๋กœ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ฃผ์˜: ์˜ˆ์‹œ์ฒ˜๋Ÿผ ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐ’์„ ์ž‘์€๋”ฐ์˜ดํ‘œ๋กœ ๋ฌถ์–ด ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ์•ˆํƒ€๊น๊ฒŒ๋„ bash๋Š” ์ด๋Ÿฐ ์ ์—์„œ ๋งค์šฐ ์ทจ์•ฝํ•˜๋ฉฐ, ์‹ค์ˆ˜๋กœ ๋‚˜๋น„๊ฐ€ ๋‚ ์•„๊ฐ€๋Š” ๊ฒƒ(์ž˜๋ชป ๋ฐฐ์น˜๋œ ๋”ฐ์˜ดํ‘œ)๋งŒ์œผ๋กœ๋„ ์ง„๋‹จํ•˜๊ธฐ ์–ด๋ ค์šด ์˜ค๋ฅ˜๋กœ ์ธํ•ด ์šฐ์ฃผ๊ฐ€ ๋ฉธ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋‹ˆํ„ฐ๋ง์„ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ฒƒ์ด ์ •์ƒ์ธ์ง€ ํ™•์ธํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

sudo chmod +x ./monitoring.sh
torsocks ./monitoring.sh

์Šคํฌ๋ฆฝํŠธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

2020-01-10 12:14:31
health-check "google front page": OK

3๋‹จ๊ณ„. ์ผ์ • ์„ค์ •

cron์—์„œ ๋ชจ๋‹ˆํ„ฐ๋ง ์ผ์ •์„ ์„ค์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

sudo crontab -e

google.com์„ ๋งค๋ถ„ ํ™•์ธํ•˜๋Š” ์ค„์„ ์ถ”๊ฐ€ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

*/1 * * * * torsocks <ะŸะฃะขะฌ ะš ะŸะะŸะšะ• ะ ะ•ะŸะžะ—ะ˜ะขะžะ ะ˜ะฏ>/monitoring.sh >> <ะŸะฃะขะฌ ะš ะŸะะŸะšะ• ะ ะ•ะŸะžะ—ะ˜ะขะžะ ะ˜ะฏ>/monitoring.log 2>&1

๋งค์ผ ์˜ค์ „ 11.00์‹œ์— ์•Œ๋ฆผ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ชจ๋‹ˆํ„ฐ๋ง ๊ธฐ๋Šฅ์„ ํ™•์ธํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ์Šคํฌ๋ฆฝํŠธ์— DAILY ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

0 11 * * * torsocks <ะŸะฃะขะฌ ะš ะŸะะŸะšะ• ะ ะ•ะŸะžะ—ะ˜ะขะžะ ะ˜ะฏ>/monitoring.sh DAILY >> <ะŸะฃะขะฌ ะš ะŸะะŸะšะ• ะ ะ•ะŸะžะ—ะ˜ะขะžะ ะ˜ะฏ>/monitoring.log 2>&1

2>&1 โ€” ์˜ค๋ฅ˜๋ฅผ ์ฃผ ์ถœ๋ ฅ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๋Š” ํ‘œ์ค€ ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ์—๋Š” ๋ชจ๋‹ˆํ„ฐ๋ง ๋กœ๊ทธ์—๋„ ๊ธฐ๋ก๋ฉ๋‹ˆ๋‹ค.

๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ €์žฅํ•˜๊ณ  ๋‹ค์Œ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ์ ์šฉํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 sudo service cron reload

์˜ˆ๋ฅผ ๋“ค์–ด, cron ์„ค์ •์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—.

๋”ฐ๋ผ์„œ ๋งค๋ถ„ ๋ชจ๋‹ˆํ„ฐ๋ง ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹คํ–‰๋˜์–ด curl์„ ํ†ตํ•ด google.com์— ์ ‘์†ํ•ฉ๋‹ˆ๋‹ค. ์ˆ˜์‹ ๋œ ์‘๋‹ต์ด ์˜ˆ์ƒ๊ณผ ๋‹ค๋ฅผ ๊ฒฝ์šฐ, ์Šคํฌ๋ฆฝํŠธ๋Š” ํ…”๋ ˆ๊ทธ๋žจ ์ˆ˜์‹ ์ž ๋ชฉ๋ก์— ์•Œ๋ฆผ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค. ํ™•์ธ ๋กœ๊ทธ๋Š” monitoring.log ํŒŒ์ผ์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ์„œ๋น„์Šค๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, ์„œ๋น„์Šค ํด๋”์— ํ•ด๋‹น ์„œ๋น„์Šค์˜ ini ํŒŒ์ผ์„ ์ƒˆ๋กœ ๋งŒ๋“ค๊ณ , ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ˆ˜์‹ ์ž ๋ชฉ๋ก์„ ๋ณ„๋„๋กœ ์ƒ์„ฑํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋‚˜๋จธ์ง€๋Š” ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค.

์ ๊ฒ€ ์ค‘์ธ ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ 1๋ถ„๋งˆ๋‹ค ์•Œ๋ฆผ์ด ์ „์†ก๋ฉ๋‹ˆ๋‹ค. ์„œ๋น„์Šค๋ฅผ ์‹ ์†ํ•˜๊ฒŒ ๋ณต๊ตฌํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ, ํ…”๋ ˆ๊ทธ๋žจ ๋ด‡ ์†์„ฑ์—์„œ ์•Œ๋ฆผ์„ ์ผ์‹œ์ ์œผ๋กœ ๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ ์Šคํฌ๋ฆฝํŠธ์˜ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ๊ณผ ๊ตฌํ˜„์„ ์ž์„ธํžˆ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ฉ”์‹œ์ง€ ํŒจํ„ด๊ณผ ๊ฐ์ •์  ์ฐธ์—ฌ

๋ด‡๊ณผ์˜ ์†Œํ†ต์„ ๋”์šฑ ํ™œ๋ฐœํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ๋ด‡์˜ ์ด๋ฆ„์„ 'Manechka'๋กœ ์ง€์ •ํ•˜๊ณ , ํ•ด๋‹น ์•„๋ฐ”ํƒ€ ์‚ฌ์ง„์„ ์ถ”๊ฐ€ํ–ˆ์œผ๋ฉฐ, ์ „๋ฌธ ํ™๋ณด ๋‹ด๋‹น์ž๋ฅผ ํ†ตํ•ด ๋ฉ”์‹œ์ง€ ํ…์ŠคํŠธ๋ฅผ ์ œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ €ํฌ๊ฐ€ ๊ฐœ๋ฐœํ•œ ๊ธฐ๋Šฅ์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์ทจํ–ฅ์— ๋งž๊ฒŒ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ :

30๋ถ„ ์•ˆ์— ์›น ์„œ๋น„์Šค๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๋ด‡: ํ…”๋ ˆ๊ทธ๋žจ + bash + cron
๋˜๋Š” ์ด๋ ‡๊ฒŒ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค:

30๋ถ„ ์•ˆ์— ์›น ์„œ๋น„์Šค๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๋ด‡: ํ…”๋ ˆ๊ทธ๋žจ + bash + cron
์™œ?

๋ด‡ ์ด๋ฆ„๊ณผ ์•„๋ฐ”ํƒ€๋Š” ๋‹ค์Œ์„ ํ†ตํ•ด ์„ค์ •๋ฉ๋‹ˆ๋‹ค. @botfather.
๋ฉ”์‹œ์ง€ ํ…œํ”Œ๋ฆฟ์€ ํด๋”์— ์žˆ์Šต๋‹ˆ๋‹ค. ํ…œํ”Œ๋ฆฟ:

  • curl-fail.txt: curl์ด 0์ด ์•„๋‹Œ ์˜ค๋ฅ˜ ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•  ๋•Œ ์ „์†ก๋˜๋Š” ๋ฉ”์‹œ์ง€์ž…๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์„œ๋น„์Šค์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
  • ๋งค์ผ.txt: ์„œ๋น„์Šค ๋ชจ๋‹ˆํ„ฐ๋ง์ด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๊ณ  ์žˆ์Œ์„ ํ™•์ธํ•˜๋Š” ์ผ์ผ ๋ฉ”์‹œ์ง€์ž…๋‹ˆ๋‹ค.
  • ์„œ๋น„์Šค ์‹คํŒจ.txt: ์„œ๋น„์Šค ์‘๋‹ต์ด ์˜ˆ์ƒ๊ณผ ๋‹ค๋ฅผ ๋•Œ ์ „์†ก๋˜๋Š” ๋ฉ”์‹œ์ง€์ž…๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์ œ๊ณต ๋ฉ”์‹œ์ง€ ํ…œํ”Œ๋ฆฟ์„ ์˜ˆ๋กœ ๋“ค์–ด ์‚ฌ์šฉ์ž ์ •์˜ ์˜ต์…˜์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
ํ…œํ”Œ๋ฆฟ์—๋Š” ์ด๋ชจ์ง€๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์•„์‰ฝ๊ฒŒ๋„ habr์—์„œ๋Š” ์ด๋ชจ์ง€๋ฅผ ํ‘œ์‹œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์ด๋ชจ์ง€๋ฅผ ์„ ํƒํ•˜๋ ค๋ฉด ๊ฒ€์ƒ‰์„ ์ด์šฉํ•˜๋ฉด ํŽธ๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋ชจ์ง€ํ”ผ๋””์•„.org:

30๋ถ„ ์•ˆ์— ์›น ์„œ๋น„์Šค๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๋ด‡: ํ…”๋ ˆ๊ทธ๋žจ + bash + cron

์ ์ ˆํ•œ ๊ธฐํ˜ธ๋ฅผ ํ…œํ”Œ๋ฆฟ ํ…์ŠคํŠธ์— ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค(์ด๊ฒƒ์€ ์ผ๋ฐ˜์ ์ธ ์œ ๋‹ˆ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค).

  1. curl-fail.txt:
    ะšะพั‚ั‘ะฝะพะบ,  ะฟะพะผะพะณะธ ะผะฝะต... 
    ะะต ะผะพะณัƒ ะดะพัั‚ัƒั‡ะฐั‚ัŒัั ะดะพ ัะตั€ะฒะธัะฐ "$MSMS_SERVICE_NAME" 
    `CURL EXIT CODE: $EXIT_CODE`

    ์šฐ๋ฆฌ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ง€์ •ํ•œ ์„œ๋น„์Šค ์ด๋ฆ„(๋ณ€์ˆ˜)์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. MSMS_SERVICE_NAME) ๋ฐ curl ์ข…๋ฃŒ ์ฝ”๋“œ๊ฐ€ ํฌํ•จ๋œ ๋‚ด๋ถ€ ์Šคํฌ๋ฆฝํŠธ ๋ณ€์ˆ˜(EXIT_CODE). ๋˜ํ•œ ๋งˆํฌ์—…์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฉ”์‹œ์ง€๋ฅผ ํฌ๋งทํ–ˆ์Šต๋‹ˆ๋‹ค. ํ…”๋ ˆ๊ทธ๋žจ ๋งˆํฌ๋‹ค์šด: "`" ๋ฌธ์ž๋Š” ๊ณ ์ • ๋„ˆ๋น„ ํ…์ŠคํŠธ๋ฅผ ๋ฌถ์Šต๋‹ˆ๋‹ค. ๋”ฐ์˜ดํ‘œ์™€ ์•„ํฌ์ŠคํŠธ๋กœํ”ผ๋Š” bash ํŠน์ˆ˜ ๋ฌธ์ž์ด๋ฏ€๋กœ "" ๋ฌธ์ž๋กœ ์ด์Šค์ผ€์ดํ”„ํ•ฉ๋‹ˆ๋‹ค. ๋ณ€์ˆ˜ ์ด๋ฆ„ ์•ž์—๋Š” "$" ๊ธฐํ˜ธ๋ฅผ ๋ถ™์ž…๋‹ˆ๋‹ค.

    ๊ฒฐ๊ณผ :

    30๋ถ„ ์•ˆ์— ์›น ์„œ๋น„์Šค๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๋ด‡: ํ…”๋ ˆ๊ทธ๋žจ + bash + cron

  2. ์„œ๋น„์Šค ์‹คํŒจ.txt:
    ะšะพั‚ั‘ะฝะพะบ, ะฟะพะผะพะณะธ ะผะฝะต... 
    ะกะตั€ะฒะธั "$MSMS_SERVICE_NAME" ะผะตะฝั ั€ะฐััั‚ั€ะพะธะป
    ะžะฝ ั€ะฐะฑะพั‚ะฐะตั‚ ะฝะตะฟั€ะฐะฒะธะปัŒะฝะพ, ะฒะพั‚ ั‡ั‚ะพ ะพะฝ ะผะฝะต ะพั‚ะฒะตั‡ะฐะตั‚:
    `$RESPONSE`

    ๊ฒฐ๊ณผ :

    30๋ถ„ ์•ˆ์— ์›น ์„œ๋น„์Šค๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๋ด‡: ํ…”๋ ˆ๊ทธ๋žจ + bash + cron

    ์—ฌ๊ธฐ์„œ๋Š” ๋˜ ๋‹ค๋ฅธ ์Šคํฌ๋ฆฝํŠธ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. RESPONSE์„œ๋น„์Šค ์‘๋‹ต์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

  3. ๋งค์ผ.txt:
    ะœะฐะปั‹ัˆ, ะฟั€ะธะฒะตั‚!
    ะฃ ะผะตะฝั ะฒัั‘ ั…ะพั€ะพัˆะพ, cะปะตะถัƒ ะทะฐ ัะตั€ะฒะธัะพะผ:
    "$MSMS_SERVICE_NAME" ะบะฐะถะดัƒัŽ ะผะธะฝัƒั‚ะบัƒ...
    ะ ะบะฐะบ ัƒ ั‚ะตะฑั ะดะตะปะฐ?
    

    ๊ฒฐ๊ณผ :

    30๋ถ„ ์•ˆ์— ์›น ์„œ๋น„์Šค๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๋ด‡: ํ…”๋ ˆ๊ทธ๋žจ + bash + cron

์ด์ œ ์Šคํฌ๋ฆฝํŠธ ๊ตฌํ˜„์œผ๋กœ ๋„˜์–ด๊ฐ€๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ชจ๋‹ˆํ„ฐ๋ง ์Šคํฌ๋ฆฝํŠธ

๋ชจ๋‹ˆํ„ฐ๋ง.sh ๊ฐ„๋‹จํ•œ ์ž๋™ ๊ฒ€์ƒ‰์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์„œ๋น„์Šค ํด๋”์—์„œ ๋ชจ๋“  ini ํŒŒ์ผ์„ ๊ฐ€์ ธ์™€์„œ ๊ฐ๊ฐ์— ๋Œ€ํ•ด ์•Œ๋ฆผ์„ ํ™•์ธํ•˜๊ณ  ๋ณด๋‚ด๋Š” ๋…ผ๋ฆฌ๋ฅผ ์ ์šฉํ•œ ๊ธฐ๋ณธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

#!/bin/bash
cd $(dirname "$0")/services

for service_ini  in $(ls *.ini); do
    bash ../msms.sh "$1" "$service_ini"
done

๋ชจ๋‹ˆํ„ฐ๋ง ์ƒํƒœ์— ๋Œ€ํ•œ ์ผ์ผ ๋ฉ”์‹œ์ง€๋ฅผ ์ƒ์„ฑํ•˜๋ ค๋ฉด DAILY ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์Šคํฌ๋ฆฝํŠธ์— ์ „๋‹ฌํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹œ์ž‘๋˜๋ฉด ํ˜„์žฌ ํด๋”๊ฐ€ services๋กœ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ini ํŒŒ์ผ์—์„œ ์„œ๋น„์Šค๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•Œ๋ฆผ ํ™•์ธ ๋ฐ ์ „์†ก ์Šคํฌ๋ฆฝํŠธ

msms.sh ์„œ๋น„์Šค๋ฅผ ํ™•์ธํ•˜๊ณ  ์•Œ๋ฆผ์„ ๋ณด๋‚ด๋Š” ๋ฐ ํ•„์š”ํ•œ ๊ธฐ๋ณธ ๋…ผ๋ฆฌ๋ฅผ ๋‹ด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ํ…”๋ ˆ๊ทธ๋žจ์œผ๋กœ ์ž‘์—…ํ•˜๊ธฐ:

# telegram endpoint
TG_API_URL="https://api.telegram.org/bot$(cat ../telegram-api-key.txt)/sendMessage"

#################################################################
# send message to telegram
# parameter: message text
#################################################################
function send_message {
    for chat_id  in $(cat ../$MSMS_RECIPIENTS); do
	curl -s -X POST --connect-timeout 10 $TG_API_URL -d chat_id=$chat_id -d parse_mode="Markdown" -d text="$1"
	echo
    done
}

ํŒŒ์ผ์— ์ €์žฅ๋œ ๋น„๋ฐ€ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…”๋ ˆ๊ทธ๋žจ REST API์— ์•ก์„ธ์Šคํ•˜๊ธฐ ์œ„ํ•œ URL์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

send_message ํ•จ์ˆ˜๋Š” curl์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด REST API๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†กํ•˜๋ฉฐ, ini ํŒŒ์ผ์— ์ง€์ •๋œ ํŒŒ์ผ์—์„œ ์ˆ˜์‹ ์ž ID๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ์ „์†กํ•˜๋Š” ๋ฐ์ดํ„ฐ์—๋Š” ๋ฉ”์‹œ์ง€ ๋งˆํฌ์—…์„ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์ ์„ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค. parse_mode="Markdown".

ํ˜„์žฌ ๋‚ ์งœ์™€ ์‹œ๊ฐ„์„ ํ‘œ์‹œํ•˜๊ณ  ini ํŒŒ์ผ์„ ๋กœ๋“œํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

echo $(date '+%Y-%m-%d %H:%M:%S')

# load variables from .ini file:
. $2

๋งค์ง๋ผ์ธ . $2 ๋‘ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌ๋œ ini ํŒŒ์ผ์„ ์ผ๋ฐ˜ ์Šคํฌ๋ฆฝํŠธ์ฒ˜๋Ÿผ ์‹คํ–‰ํ•˜๊ณ , ๊ทธ ์•ˆ์— ์ง€์ •๋œ ๊ฐ’์„ ํ™˜๊ฒฝ ๋ณ€์ˆ˜์— ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.

๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์ง€์ •๋œ ๊ฒฝ์šฐ ํŒŒ์ผ์—์„œ ์˜ˆ์ƒ ์‘๋‹ต์„ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. MSMS_EXPECTED_FILE:

if [ -n "$MSMS_EXPECTED_FILE" ]; then
 MSMS_EXPECTED="$(cat "$MSMS_EXPECTED_FILE")"
fi

ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์•Œ๋ฆผ์„ ๋ณด๋‚ด ์„œ๋น„์Šค ์ ๊ฒ€์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

RESPONSE="$(eval curl $MSMS_CURL_PARAMS "$MSMS_SERVICE_ENDPOINT")"
EXIT_CODE=$?
if [[ $EXIT_CODE != 0 ]]; then
    echo health-check "$MSMS_SERVICE_NAME" FAILED: CURL EXIT WITH $EXIT_CODE
    MESSAGE="$(cat ../templates/curl-fail.txt)"
    MESSAGE=$(eval echo $MESSAGE)
    send_message "$MESSAGE"
elif [[ "$RESPONSE" != "$MSMS_EXPECTED" ]]; then
    echo health-check "$MSMS_SERVICE_NAME" FAILED: "$RESPONSE"
    MESSAGE="$(cat ../templates/service-fail.txt)"
    MESSAGE=$(eval echo $MESSAGE)
    send_message "$MESSAGE"
else
    echo health-check "$MSMS_SERVICE_NAME": OK
fi

๋จผ์ € ๋ณ€์ˆ˜์— ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค RESPONSE ์ด ์„œ๋น„์Šค์— ๋Œ€ํ•ด curl ๋ช…๋ น์„ ์‹คํ–‰ํ•œ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค.

ํ‘œํ˜„ EXIT_CODE=$? ๋งˆ์ง€๋ง‰ ๋ช…๋ น(์˜ˆ: curl)์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ณ€์ˆ˜์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์•Œ๋ฆผ์„ ๋ณด๋‚ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, ํ•ด๋‹น ํŒŒ์ผ์—์„œ ํ…œํ”Œ๋ฆฟ์„ ์ฝ์–ด ์ˆ˜์‹ ์ž์—๊ฒŒ ์ „์†กํ•ฉ๋‹ˆ๋‹ค. send_message.

๋งˆ์ง€๋ง‰ ๋ธ”๋ก์€ DAILY ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

if test "$1" = "DAILY"; then
    echo health-check "$MSMS_SERVICE_NAME" DAILY
    MESSAGE="$(cat ../templates/daily.txt)"
    MESSAGE=$(eval echo $MESSAGE)
    send_message "$MESSAGE"
fi

๋ชจ๋‹ˆํ„ฐ๋ง ์ž์ฒด์˜ ๊ธฐ๋Šฅ์„ ํ™•์ธํ•˜๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋ƒ…๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž ID ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ

์ˆ˜์‹ ์ž-์„ค์ •.sh ๋ด‡์—๊ฒŒ ์ „๋‹ฌ๋œ ์ตœ์‹  ๋ฉ”์‹œ์ง€๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด Telegram API๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

curl -s https://api.telegram.org/bot$(cat telegram-api-key.txt)/getUpdates 
| python recipients-setup.py

์ด ํ•จ์ˆ˜๋Š” ํŒŒ์ด์ฌ ๋งค์ง์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ชฉ๋ก์„ ๋ฉ‹์ง€๊ฒŒ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ๊ผญ ํ•„์š”ํ•œ ๊ฒƒ์€ ์•„๋‹ˆ๋ฉฐ, ๋ช…๋ น์ด ์ถœ๋ ฅํ•˜๋Š” JSON ํŒŒ์ผ์—์„œ ์›ํ•˜๋Š” ID๋ฅผ ๊ฐ€์ ธ์˜ค๋ฉด ๋ฉ๋‹ˆ๋‹ค.

torsocks curl -s https://api.telegram.org/bot$(cat telegram-api-key.txt)/getUpdates

๊ฒฐ๋ก 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ธฐ์„ฑ ์Šคํฌ๋ฆฝํŠธ์™€ ๋ฉ”์‹œ์ง€ ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋‹ˆํ„ฐ๋งํ•  ์„œ๋น„์Šค์™€ ์•Œ๋ฆผ ๋ชฉ๋ก๋งŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ด‡์— ๋Œ€ํ•œ ์ƒˆ๋กœ์šด "๊ฐœ์„ฑ"์„ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ๊ณ , ์ œ์•ˆ๋œ ํŠน์„ฑ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ง์ ‘ ๊ฒฐ์ •์„ ๋‚ด๋ฆด ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ถ”๊ฐ€ ๊ฐœ๋ฐœ ์˜ต์…˜์œผ๋กœ ๋ด‡ ์ž์ฒด์—์„œ ๋ชจ๋‹ˆํ„ฐ๋ง์„ ๊ตฌ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ข‹์ง€๋งŒ, ํŒŒ์ด์ฌ ์—†์ด๋Š” ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ ์ €๋ณด๋‹ค ๋จผ์ € ๊ฐœ๋ฐœํ•œ๋‹ค๋ฉด, ํ’€ ๋ฆฌํ€˜์ŠคํŠธ๋ฅผ ์–ด๋””์— ์—…๋กœ๋“œํ•ด์•ผ ํ• ์ง€ ์•„์‹œ๊ฒ ์ฃ ? ๐Ÿ™‚

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€