# 서비스 모니터링하기

**모니터**는 일정에 따라 HTTP 요청이나 TCP 연결로 서비스를 확인하고, 서비스가 멈추면 상태 페이지에 알립니다. 확인은 **프로브 위치**에서 실행됩니다. 프로브는 서비스에 닿을 수 있는 머신에서 실행하는 작은 에이전트입니다. Mocco에 작업을 요청하고 관찰한 결과를 보고하므로 인바운드 포트가 필요 없습니다.

먼저 컴포넌트가 있는 상태 페이지가 필요합니다([상태 페이지 운영하기](https://www.mocco.club/docs/ko/articles/dn83zy-status-page)). 모니터는 연결된 컴포넌트가 보여 주는 상태를 바꿉니다.

## 1. 프라이빗 위치 만들기

위치는 워크스페이스에 속하므로 모든 프로젝트가 쓸 수 있습니다. 프로젝트의 **Status page** 섹션에서 **Locations**를 엽니다. 워크스페이스의 모든 멤버가 목록을 볼 수 있고, 위치를 만들고 교체하고 비활성화하는 일은 소유자와 관리자가 합니다.

**New private location**을 선택하고 **name**("Office network")과 **code**를 입력합니다. Mocco가 이름에서 코드를 제안합니다. 코드는 소문자, 숫자, 하이픈으로 이루어지며 워크스페이스 안에서 고유해야 합니다.

![새 프라이빗 위치: 이름과 코드](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/08d9c7cd-1830-4c56-b8d9-bd38fe14232d/new-location.png)

그러면 Mocco가 위치의 **토큰**을 한 번만 보여 주고, 그 토큰으로 프로브를 실행하는 명령도 함께 보여 줍니다. 지금 복사하세요. Mocco는 토큰의 해시만 보관하므로 다시 보여 줄 수 없습니다.

![한 번만 보이는 토큰과 프로브를 실행하는 Docker, Node 명령](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/50ef6ed9-a9d9-4381-b5d6-283c07841b89/location-token.png)

## 2. 프로브 실행하기

확인할 서비스에 닿을 수 있고 Mocco로 아웃바운드 HTTPS 호출을 보낼 수 있는 머신에서, 화면에 나온 명령 중 하나를 실행합니다.

```bash
docker run -d --restart unless-stopped \
  -e MOCCO_URL=https://www.mocco.work -e MOCCO_PROBE_TOKEN=mpl_... ghcr.io/fi-workers/mocco-probe
# or, with Node 22
MOCCO_URL=https://www.mocco.work MOCCO_PROBE_TOKEN=mpl_... npx @mocco/probe
```

패키지와 이미지가 공개되기 전에는 Mocco 체크아웃에서 실행합니다. `yarn workspace @mocco/probe build`를 실행한 뒤 같은 두 변수로 `node packages/probe/dist/cli.js`를 실행하세요.

프로브가 모든 통신을 먼저 시작합니다. Mocco에 작업을 요청하고 관찰한 결과를 전송하며, Mocco가 프로브에 연결하는 일은 없습니다. 그래서 머신이 Mocco로 아웃바운드 HTTPS 호출(443 포트)만 보낼 수 있으면 NAT나 방화벽 뒤에서도 실행됩니다. 인바운드 포트도, 공개 주소도 필요 없습니다.

프로브가 폴링을 시작하면 위치에 **Seen just now**와 프로브의 버전이 표시됩니다. 같은 토큰을 쓰는 프로브가 둘이면 그 위치의 작업을 나눠 처리합니다.

![워크스페이스의 위치 목록: 프라이빗 위치가 방금 확인됨](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/23f2d901-218a-4227-9ba6-20c5e367cbcf/locations.png)

모니터가 실행 중인 위치의 프로브가 3분 동안 폴링하지 않으면 위치에 **Silent**가 표시되고, Mocco가 알림 규칙을 통해 **Location silent** 알림(`status.location.unhealthy`)을 보냅니다. 그 위치의 모니터는 더 이상 프로브를 기다리지 않습니다. 다른 위치가 라운드를 판정하고, 이 위치만 실행하는 라운드는 알 수 없음(unknown)으로 남으며 다운타임으로 계산되지 않습니다. 프로브가 다시 폴링하면 **Location back** 알림이 옵니다.

**Rotate token**은 새 토큰을 발급하고 이전 토큰을 즉시 중지합니다. 이전 토큰으로 실행 중인 프로브는 종료되므로 새 토큰으로 다시 시작하세요. **Disable**은 위치를 영구히 중지합니다. 이후에는 어떤 모니터도 그 위치를 쓸 수 없습니다.

## 3. 모니터 만들기

**Monitors**를 열고 **New monitor**를 선택합니다.

![사무실 네트워크에서 헬스 엔드포인트를 확인하는 새 HTTP 모니터. 다운 상태일 때 REST API는 major outage로 표시됩니다](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/fa57112e-033f-48a8-a334-ab21f1bf70e4/new-monitor.png)

- **Check**: **HTTP**는 메서드(GET, HEAD, POST. POST는 본문 포함)로 URL에 요청을 보냅니다. **TCP**는 호스트와 포트에 연결을 엽니다.
- **Expected status codes**: 통과로 인정하는 응답 코드입니다. 예를 들어 `200, 204`처럼 입력합니다. 비워 두면 모든 2xx를 받아들입니다.
- **Keyword**: 선택 사항입니다. 응답 본문에 특정 단어가 있어야 하거나 없어야 한다는 조건을 겁니다.
- **Slow above (ms)**: 선택 사항입니다. 이보다 느린 응답은 통과하지만 모니터를 **degraded**로 만듭니다.
- **Warn before certificate expiry (days)**: 선택 사항입니다. `https` URL에서 TLS 인증서가 만료되기 며칠 전에 경고할지 정합니다. Mocco는 그 일수가 남았을 때 한 번 경고하고, 7일, 3일, 1일 전에 다시 경고합니다.
- **Timeout**: 한 번의 확인에 허용하는 시간입니다. 최대 30초입니다.
- **Every (s)**: 실행 주기입니다. 최소 60초마다입니다.
- **Down after**와 **Up after**: 모니터가 다운되려면 연속으로 몇 라운드를 실패해야 하는지, 다시 업이 되려면 연속으로 몇 라운드를 통과해야 하는지 정합니다. 기본값은 2이므로 한 번의 나쁜 응답으로 누군가를 호출하지 않습니다.
- **Locations**: 모니터를 실행할 위치입니다. 위치가 여럿이면 **Locations that must agree**가 보고한 위치 중 몇 곳이 실패(또는 통과)해야 그 라운드를 실패(또는 통과)로 볼지 정합니다. 아무것도 보내지 않은 위치는 실패로 계산하지 않습니다. **Any one**을 고르지 않으면, 여러 위치의 모니터는 최소 두 곳이 실패해야 다운됩니다. 한 위치의 네트워크 문제가 모니터를 다운시키지 않게 하려는 장치입니다.
- **While down**: 모니터가 다운일 때 각 컴포넌트가 보여 줄 상태입니다. **Not affected**를 고를 수도 있습니다.
- **When it goes down**: 인시던트를 열지 않음, **draft** 인시던트(기본값), **published** 인시던트 중에서 고릅니다.

새 모니터는 첫 라운드가 끝날 때까지 **Pending**입니다. 첫 라운드는 즉시 실행됩니다.

![프로젝트의 모니터 목록: 상태, 대상, 컴포넌트](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/ce727131-42f5-4441-be74-026e07493e92/monitors.png)

## 4. 실패하면 일어나는 일

라운드가 실패하면 모니터는 **Suspect**가 되고 곧바로 다시 확인합니다. **Down after** 라운드가 지나도 계속 실패하면 **Down**이 됩니다.

- 연결한 컴포넌트가 콘솔과 공개 페이지에서 선택한 영향도를 보여 줍니다.
- 인시던트가 열립니다. "API health is down"이라는 제목으로 **Investigating** 상태이며, 해당 컴포넌트 대부분이 속한 페이지에 열립니다. **draft**는 콘솔에만 남고 공개 페이지에는 나가지 않으므로, 검토한 뒤 직접 업데이트를 게시하세요. 컴포넌트가 점검 시간에 걸려 있는 동안에는 게시(published)로 고른 인시던트도 초안으로 열립니다.
- Mocco가 [알림 규칙](https://www.mocco.club/docs/ko/articles/eriac3-mocco-events)을 통해 **Down** 알림(`status.monitor.down`)을 보냅니다. 알림에는 호스트와 포트만 들어가고 URL의 경로, 쿼리, 자격 증명은 들어가지 않습니다.

![두 번 실패한 뒤 다운된 모니터와 그 모니터가 연 초안 인시던트](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/45852d69-4374-401f-be12-8d738efdf806/monitor-down.png)

확인이 다시 통과하면 모니터는 **Recovering**이 되고, 인시던트에는 **Monitoring** 업데이트가 달립니다. **Up after** 라운드를 통과하면 **Up**이 됩니다. 인시던트는 **Resolved**가 되고, 컴포넌트는 원래 상태로 돌아가며, **Recovered** 알림이 갑니다. 오경보(Suspect 후 Up)는 아무것도 보내지 않습니다. 느린 응답은 모니터를 **Degraded**로 만들고 **Degraded** 알림을 보냅니다.

인증서 만료 임박은 장애가 아니라 경고입니다. 남은 일수가 설정한 값 아래로 내려가면 Mocco가 기준마다 한 번씩 **Certificate expires in N days** 알림(`status.monitor.tls_expiring`)을 보내고, 모니터는 **Up**을 유지합니다. 인증서를 갱신하면 경고가 초기화됩니다. 이미 만료된 인증서는 확인에 실패하므로 모니터는 다른 실패와 똑같이 다운됩니다.

모니터 페이지에는 최근 라운드와 모든 상태 변경이 나옵니다. **Pause**는 확인을 멈추고(예: 서비스를 옮기는 동안), **Resume**은 다시 시작합니다. **Edit**은 상태를 유지한 채 설정을 바꿉니다.

![모니터의 라운드와 상태 변경: up에서 suspect, down, recovering을 거쳐 다시 up으로](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/be5119b2-9aab-47a3-9e58-f1aefe0c8da7/monitor-recovered.png)

## 5. 배포 후

프로젝트에 연결된 저장소의 실행이 릴리스되면(게이트를 통과해 성공하면) Mocco가 15분 동안 프로젝트의 모니터를 **지켜봅니다**. 이 동안 모니터는 1분이 아니라 30초마다 확인합니다. 모니터 페이지에 어떤 실행 이후를 지켜보는지, 언제까지인지가 표시됩니다.

![배포 후 지켜보는 모니터: 감시가 끝날 때까지 30초마다 확인](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/2fbf23d8-b266-4bc1-92e1-36312adcd096/deploy-watch.png)

감시 중에 모니터가 다운되면, 모니터가 연 인시던트에 배포 몇 분 안에 실패하기 시작했다는 내용이 적히고, 해당 실행은 인시던트의 **Recent deploys** 아래에 **Suspected**로 표시됩니다. 실행 자체의 타임라인에도 실패한 확인이 기록됩니다. 실행 자체는 바뀌거나 롤백되지 않습니다.

파이프라인 단계에서 `POST /v1/monitors/{id}/check`와 `status:write` 권한이 있는 시크릿 키로 즉시 라운드를 요청할 수도 있습니다.

## 6. cron 작업과 워커를 위한 하트비트

프로브는 야간 백업이나 큐 워커를 볼 수 없습니다. **하트비트** 모니터는 반대로 동작합니다. 작업이 실행될 때마다 Mocco에 핑을 보내고, 핑이 끊기거나 실패를 보고하면 모니터가 다운됩니다. 프로브도 위치도 필요 없습니다.

**New monitor**를 선택한 뒤 **Check: Heartbeat**를 고릅니다.

- **Expected every (min)**: 작업이 실행되는 주기입니다. 매일 실행하는 작업이면 1440처럼 입력합니다.
- **Grace (min)**: 핑이 얼마나 늦어도 누락으로 보지 않을지 정합니다. 예를 들면 30입니다.
- **While down**과 **When it goes down**은 다른 모니터와 같습니다.

![매일 실행하는 백업용 새 하트비트 모니터: 1440분마다 기대, 유예 30분](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/6c76061d-26a2-45cd-bc46-28145c3a7aef/new-heartbeat.png)

**Create monitor**를 선택하면 Mocco가 모니터의 **ping URL**을 한 번만 보여 주고, 복사해 쓸 명령도 함께 보여 줍니다. URL의 토큰이 유일한 자격 증명이고 Mocco는 해시만 보관하므로 지금 복사하세요.

![한 번만 보이는 핑 URL과 curl, crontab, Node 스니펫](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/31b221c2-a1af-48c5-8f88-3a43b13836ef/heartbeat-ping-url.png)

작업에서 `GET` 또는 `POST`로 핑을 보냅니다(API 키는 필요 없습니다).

```bash
# when the job finishes
curl -fsS -m 10 --retry 3 https://…/v1/ping/mhb_...
# or report the start, then the exit code (0 is a success, anything else is down at once)
curl -fsS -m 10 --retry 3 https://…/v1/ping/mhb_.../start
/usr/local/bin/backup.sh
curl -fsS -m 10 --retry 3 https://…/v1/ping/mhb_.../$?
```

`/fail`은 코드 없이 실패를 보고합니다. Node에서는 `@mocco/node`가 함수를 감싸 같은 일을 합니다. `await heartbeat('mhb_...', { baseUrl }).wrap(async () => runBackup())`는 `/start`를 핑하고, 이어서 성공을 핑하며, 함수가 예외를 던지면 `/fail`을 핑합니다. 전달하지 못한 핑은 로그에 남고 작업을 중단시키지 않습니다.

주기와 유예 시간을 합친 시간 동안 핑이 오지 않으면(핑을 한 번도 받지 않은 새 모니터는 생성 시점부터 셉니다), 또는 핑이 실패를 보고하면 즉시 모니터가 **Down**이 됩니다. 다음 성공 핑이 오면 **Up**이 되며, **Down after**나 **Up after**를 기다리지 않습니다. 컴포넌트, 인시던트, 알림은 다른 모니터와 같게 따라가고([4. 실패하면 일어나는 일](#4-what-happens-when-it-fails)), 다운타임은 가동 시간 이력에 반영됩니다.

모니터 페이지에는 마지막 핑이 온 시각과 마지막 실행에 걸린 시간(`/start`부터 종료까지)이 나옵니다. 각 상태 변경에는 이유가 적힙니다. 핑, 종료 코드가 있는 실패, 제때 오지 않은 핑 중 하나입니다.

![하트비트 페이지: 주기와 유예 시간, 마지막 핑, 마지막 실행 시간, 핑과 누락된 핑에 따른 변경](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/c17e60b6-94c0-4d50-acbd-f107394a4845/heartbeat.png)

**Replace ping URL**은 새 URL을 발급하고 이전 URL은 즉시 중지하므로 작업을 업데이트하세요. 일시 중지된 하트비트도 핑을 받고 표시하지만 상태는 바뀌지 않습니다. **Resume** 후에는 주기와 유예 시간이 한 번 모두 지나야 누락된 핑으로 칩니다. 핑은 URL당 5초에 5회로 제한됩니다.

## 기록되는 내용

모니터 생성, 편집, 일시 중지, 재개, 삭제, 하트비트의 핑 URL 교체, 위치 생성, 교체, 비활성화는 모니터가 연 인시던트와 그 업데이트와 함께 워크스페이스의 [감사 로그](https://www.mocco.club/docs/ko/articles/2yiscf-audit-log)에 기록됩니다.
