일이 지났습니다. 시의성에 유의하세요
서문
최근 Github Pages와 Github Actions를 함께 사용하는 방법을 연구해보았는데, 개인 블로그 운영에 매우 적합하다고 생각되어 이 글을 작성하게 되었습니다.
기존에는 블로그 소스 코드를 리포지토리에 직접 올리고 Github Pages에서 제공하는 기본 Jekyll을 사용하면서 커스텀 도메인을 설정했습니다. 하지만 이 방식에는 다음과 같은 문제점들이 있었습니다:
- 소스 코드를 숨길 수 없음. _post 디렉토리에 있는 글들은 누구나 자유롭게 복사하여 자신의 콘텐츠로 사용할 수 있습니다.
- 수정 기록을 숨길 수 없음. 블로그에서 일부 내용을 삭제하더라도, 다른 사람들은 리포지토리 소스 코드의 히스토리를 통해 해당 파일의 변경 내역을 확인할 수 있어 모든 수정 사항이 노출됩니다.
- Gitalk 사용 불가. 위 두 문제는 Github Pro 이상의 유료 계정으로 해결할 수 있지만(이 경우 프라이빗 리포지토리에서 Github Pages 사용이 가능), 이렇게 되면 issue에 댓글을 작성해야 하는 Gitalk과 같은 도구를 사용할 수 없게 됩니다.
- 로컬과 온라인 빌드 결과 불일치 또는 오류 발생 시 문제 해결 불가. Github Pages에서 제공하는 Jekyll은 블랙박스 형태로 제공되기 때문에 문제를 추적할 수 없습니다.
- 일부 커스텀/서드파티 플러그인 사용 불가. Github Pages는 일부 플러그인만 지원하기 때문에, 홈페이지뿐만 아니라 카테고리별 글도 페이지네이션할 수 있는 jekyll-paginate v2와 같은 플러그인은 사용할 수 없습니다.
위와 같은 이유로, 저는 컴파일된 소스 코드를 Github Pages의 내용으로 사용하기로 결정했으며, 원본 소스 코드는 사용하지 않기로 했습니다. 블로그 저장소에는 이미 Gitalk으로 생성된 일부 issue 댓글이 있었기 때문에, 새로운 저장소를 생성하여 원본 소스 코드를 보관하는 곳으로 설정하고 비공개로 설정했습니다. 그리고 기존 저장소는 여전히 Github Pages로 게시하는 저장소로 유지하되, 컴파일된 소스 코드만 게시하도록 했습니다. 이렇게 하면 원래의 댓글 데이터를 보존할 수 있을 뿐만 아니라, 앞서 언급한 여러 문제를 피할 수 있습니다. 제가 매번 소스 코드를 컴파일하여 Github Pages에 게시할 때 force 푸시를 사용하기 때문에 파일 수정 기록을 확인할 수 없어, 어느 정도 프라이버시를 보호하고 복제 비용을 증가시킬 수 있습니다. 아래는 이 과정에 대한 설명입니다.
전체 프로세스
기본적인 프로세스는 다음과 같습니다. 기존 저장소를 A라고 하고, 새로운 원본 소스 코드를 보관하는 비공개 저장소를 B라고 가정합니다. 새로운 푸시가 발생하면 B 저장소의 Github Actions가 트리거되고, 해당 Actions는 컴파일된 소스 코드, 즉 _site 폴더의 내용을 A 저장소로 푸시합니다. A 저장소는 이미 Github Pages로 설정되어 있고 사용자 정의 도메인이 구성되어 있기 때문에 추가적인 처리가 필요하지 않습니다.
상세 과정
Github Actions에서 몇 가지 개념을 명확히 이해해야 합니다:
계층 구조
크기 순서대로 다음과 같습니다:
- 스크립트 자체: actions에서 실행될 ci.yml 파일 자체입니다.
- 작업: 구성된 jobs로, jobs는 기본적으로 병렬로 실행되며 needs 키워드를 사용하여 다른 jobs에 대한 의존성을 설정할 수 있습니다.
- 단계: steps로, jobs에서 실행되는 각 단계이며 순차적으로 실행됩니다. 각 step은 자신의 환경 컨텍스트에서 실행됩니다. 하나의 jobs에는 무제한의 steps가 있을 수 있습니다.
- 액션: 모든 steps가 액션을 실행하는 것은 아니지만, 액션은 steps 내에서 실행되는 구체적인 명령입니다. 예를 들어 현재 디렉토리 출력, 의존성 설치 등이 있습니다.
다른 사람의 step 사용하기
Action을 사용하면 다른 사람이 작성한 step을 활용할 수 있어 직접 작성할 필요가 없습니다. 예를 들어, 브랜치를 체크아웃해야 하는 경우 다음과 같이 간단히 처리할 수 있습니다:
1 | |
with는 관련 매개변수이며, 해당 step의 설명에서 자세한 내용을 확인할 수 있습니다.
데이터 암호화
ci 파일에서 Personal Token이나 기타 민감한 데이터가 공개되는 것을 원치 않을 것입니다. 따라서 암호화 후 이름으로 참조하는 방식을 사용해야 합니다. 여기서 주의할 점은 암호화 데이터 간의 차이입니다:
- GITHUB_TOKEN: 자신의 저장소에서 빌드나 actions 작업만 수행하는 경우, 저장소 설정에서 별도의 조치가 필요하지 않습니다. actions가 실행될 때 Github은 자동으로 GITHUB_TOKEN이라는 환경 변수를 생성하며, 현재 저장소에 코드를 푸시하는 등 인증이 필요한 곳에서 사용할 수 있습니다.
- Personal Token: 현재 ci가 A 저장소에서 실행되지만 B 저장소에 작업을 수행해야 하는 경우, B 저장소 관리자가 생성한 Personal Token이 필요하며 일부 권한을 할당하면 됩니다.
- 사용자 정의 암호화: 두 번째 단계에서 B 저장소에 Personal Token이 생성되었다면, A 저장소에서 이를 어떻게 사용할까요? 이때 secret(사용자 정의 암호화)를 활용해야 합니다. A 저장소 설정에서 B_REPO_TOKEN과 같은 변수 이름을 정의한 후, 앞서 얻은 Personal Token을 복사해 넣으면 secret.B_REPO_TOKEN 방식으로 참조할 수 있습니다.
구체적인 단계
위에서 이미 상세히 설명했으므로, 아래에서는 파일을 나열하고 각각을 분석하겠습니다. 필요할 때 해당 내용을 복사하여 약간 수정하면 됩니다:
1 | |
여기서 마지막 단계에 대해 설명이 필요한데, X_BLOG_SITE은 제가 정의한 암호화 데이터로, 값은 설정된 Personal Token입니다. 또한 원격 저장소에 push할 때, 해당 CI가 현재 저장소만 조작한다면 저장소 이름을 하드코딩하지 않고 환경 변수를 다음과 같이 작성할 수 있습니다:
1 | |
즉 github.XXX를 사용하여 관련 정보를 참조할 수 있으며, 여기에서 더 많은 컨텍스트 매개변수 설명을 확인할 수 있습니다.
travis와의 차이점
이전에 Travis를 사용한 적이 있는데, 두 가지의 개념은 기본적으로 거의 비슷합니다. 가장 눈에 띄는 차이점은 Github Actions는 다른 사람이 작성한 actions를 참조할 수 있도록 허용한다는 점입니다. 이는 마치 다른 사람의 패키지를 'require’할 수 있는 것과 같아서, 해당 패키지를 유지보수할 필요 없이 바로 사용할 수 있습니다. 따라서 활용 방법이 더 다양하고 설정도 더 적으며 재사용성도 더 높습니다.
저는 인생의 중요한 선택의 기로에 섰을 때, 누군가 최선의 방법을 알려주어 소중한 시간을 헛되이 보내지 않기를 바라곤 합니다. 그런 마음으로 저는 자주 블로그를 쓰며, 광활한 인터넷의 이 작은 구석에 제게는 단 한 번뿐인 인생 경험을 기록하여 도움이 필요한 분들에게 도움이 되기를 바랍니다.