이번 블로그에서는 내부 개발자 포털(IDP)인 Port를 사용해 사내 블로그 포스팅 프로세스를 자동화한 썰을 풉니다. 인포그랩에서는 블로그를 포스팅하기 위해 매일 10분 이상씩 하던 단순 반복 작업을 클릭 한 번에 동작하도록 했습니다. 그 결과, 개발자, 테크니컬 라이터의 스트레스를 줄여 더 중요한 업무에 집중할 수 있는 환경을 만들었습니다.
반복 작업을 줄이는 건 단순히 시간만 단축하는 것이 아닙니다. 수많은 사람이 단순 작업을 반복하느라 더 유용한 가치를 만드는 데 시간을 쓰지 못하고 있습니다. 이러한 작업을 줄이면 더 큰 가치를 창출하는 업무 시간을 확보할 수 있습니다. 이에 인포그랩에서는 수많은 교육 자료와 블로그의 배포 프로세스를 자동화하여 멤버들이 더 가치 있는 작업에 주력하도록 돕습니다.
내부 개발자 포털이란?
내부 개발자 포털(IDP)은 사내의 수많은 도구와 기능, 그리고 프로세스를 통합한 플랫폼입니다. 이는 개발자가 클릭 한 번으로 인프라를 배포하거나, 자신이 만든 서버를 통합적으로 관찰할 수 있도록 합니다. 개발자는 Git을 사용해 코딩하고, 내부 개발자 포털의 버튼만 클릭하면 됩니다.
내부 개발자 포털은 아래 세 가지 구성 요소로 나눌 수 있습니다.
- 블루프린트 : 인프라나 소프트웨어 등을 추상적으로 정의한 스키마입니다. Kubernetes 클러스터나 네임스페이스부터 배포 환경, 블로그 포스트까지 필요에 따라 무엇이든 정의할 수 있습니다.
- 서비스 카탈로그 : 블루프린트를 바탕으로 실제 어떻게 각 요소(entity)가 구성되어 있는지를 확인하는 창입니다. “특정 네임스페이스에 엮여 있는 Git 프로젝트들” 처럼 요소끼리 어떻게 연결되었는지를 그래프로 확인할 수 있습니다.
- 셀프 서비스 : 수동 프로세스를 자동화해 만든 하나의 작업입니다. 예시로는, “네임스페이스 지우기”, “파이프라인 동작시키기” 등이 있습니다. 작업을 실행하면 백엔드 서버(Webhook, GitHub Action, …)가 동작합니다.

내부 개발자 포털 을 인포그랩에 적용하기
저는 내부 개발자 포털을 처음 접하고 제일 먼저 ‘지금 쓰고 있는 블로그를 배포하는 프로세스’를 자동화하고 싶었습니다. 그래서 사내 토이 프로젝트로 ‘내부 개발자 포털을 이용한 블로그 포스팅 자동화 시스템’을 만들었습니다. 이번 프로젝트의 소스 코드는 이곳에서 확인할 수 있습니다.
현재 프로세스 분석하기
인포그랩이 현재 어떻게 블로그 포스팅을 하고 있는지 정리했습니다. 아래는 블로그 하나를 작성하기 위해 거쳐야 하는 수많은 단계를 나열한 것입니다. ‘블로그를 노션에 작성’하는 프로세스는 별다른 개선 사항이 없었습니다. 하지만 노션에 있는 블로그를 Git으로 배포하는 프로세스는 다음 문제가 있었습니다.
첫째, 비개발 직군 멤버가 회사 블로그를 쓰기 불편했습니다. 회사 블로그는 개발자들만 작성하지 않습니다. 오늘날 테크니컬 라이터, 기획자, 디자이너 등 여러 직군의 사람이 자신의 노하우를 블로그로 작성합니다. 익숙하지 않은 마크다운 문법과 Git을 사용하면 많은 스트레스를 받습니다.
둘째, 불필요한 반복 작업이 많습니다. VS Code, Notion, GitLab 등 여러 도구를 사용해 자잘한 수정을 거쳐야 합니다. 특히 이미지의 이름을 바꾸는 일은 정말 고역입니다. 하지만 이러한 부분이 자동화가 불가능한 영역이 아니기에 개선하고 싶었습니다. 또한 오로지 노션과 내부 개발자 포털만 가지고 블로그를 손쉽게 배포하고 싶었습니다.
1 단계. 노션에 블로그를 작성
2 단계. 노션에 있는 블로그를 코드로 작성 후 푸시
회사의 컨벤션 정리하기
인포그랩에는 효율적인 협업을 위해 많은 컨벤션이 있습니다. 예를 들어 GitLab 이슈를 만들 때는 이슈 제목을 [Blog] <title>
형식으로 만들고, 브랜치 이름은 issue<issue_number>-<file-name>
형식으로 만들어야 합니다. 또한 지난 포스팅에서도 언급했듯이 효과적인 커밋 컨벤션을 지켜야 합니다. 저는 내부 개발자 포털로 커밋 컨벤션, 이슈와 브랜치 컨벤션 등을 자동화하기로 했습니다.
커밋 컨벤션
export function formatCommitMessage(title: string, issueIid: number) {
return `📝 Docs(블로그): ${title} 포스트
#${issueIid}`
}
블로그 이슈 컨벤션
export function formatIssueDescription(title: string) {
return `
# 다음 지침을 따르십시오.
- [x] 제목이 간결한가?
- [x] 적절한 feature 에픽을 선택하였는가?
- [x] 적절한 마일스톤을 선택하였는가?
- [x] 적절한 레이블을 추가하였는가? (필수: \`type\`)
- [ ] 연관 아이템을 연결하였는가?
# 설명
${title}`
}
블로그 메타데이터
export function formatBlogMetadata(data: BlogMetadata) {
return `
summary: ${data.summary}
id: ${data.id}
categories: ${data.categories.join(', ')}
tags: ${data.tags.join(', ')}
status: ${data.status}
authors: ${data.author}
`
}
그 밖의 네이밍 규칙들
- 이슈 제목:
[Blog] <블로그 제목>
- 브랜치 이름:
issue<issue_number>-<file-name>