All about

github action을 통해서 Unit test를 하는데 GPU가 필요해서, 그냥 가지고 있는 우분투 서버를 이용하기로 함. 이 글은 이미 repo에 github action이 한 개 이상 설정되어 있음을 가정함. 만약 설정이 안되어 있다면 링크를 읽어보고 하기 바람(설정이 안되어 있다면 github UI가 약간 다름)

 

1. github repository에서 "Actions" -> "New workflow" 를 클릭하고 yml 에 아래 내용을 입력

 

name: Testing

on: push

jobs:
  testing:
    runs-on: self-hosted

    steps:
    - uses: actions/checkout@v2
    - name: Functionality test
      shell: bash -l {0}
      run: make action_test # 이 자리에 unit test 실행 코드가 들어 있으면 됨

 

2. github action을 실행할 docker container 이미지 파일을 빌드해야한다. unit test 환경이 바뀔 수 있으니(library 등) 일단 unit test 용 base image를 빌드하고, base image 위에 종속 라이브러리를 설치한 docker image를 한개 더 빌드한다. base image 를 위한 Dockerfile은 아래와 같고, 첫번째 줄 이외에는 수정하지 않는다.

 

FROM ubuntu # 특별히 사용하는 base image가 있다면 변경함. 나머지 아래는 건들지 않는다.

ARG GIT_VERSION="2.29.0"
ARG DUMB_INIT_VERSION="1.2.2"
ARG DOCKER_KEY="7EA0A9C3F273FCD8"

ENV DOCKER_COMPOSE_VERSION="1.27.4"
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8

SHELL ["/bin/bash", "-o", "pipefail", "-c"]
ENV DEBIAN_FRONTEND=noninteractive
# hadolint ignore=DL3003,DL4001
RUN apt-get update && \
  apt-get install -y --no-install-recommends \
    awscli \
    curl \
    tar \
    unzip \
    apt-transport-https \
    ca-certificates \
    sudo \
    gnupg-agent \
    software-properties-common \
    build-essential \
    zlib1g-dev \
    gettext \
    liblttng-ust0 \
    libcurl4-openssl-dev \
    inetutils-ping \
    jq \
    wget \
    dirmngr \
    openssh-client \
    locales \
    python3-pip \
  && pip3 install --no-cache-dir awscliv2 \
  && locale-gen en_US.UTF-8 \
  && dpkg-reconfigure locales \
  && c_rehash \
  && cd /tmp \
  && [[ $(lsb_release -cs) == "xenial" ]] && ( wget --quiet "https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/dumb-init_${DUMB_INIT_VERSION}_$(uname -i | sed 's/x86_64/amd64/g').deb" && dpkg -i dumb-init_*.deb && rm dumb-init_*.deb ) || ( apt-get install -y --no-install-recommends dumb-init ) \
  && curl -sL https://www.kernel.org/pub/software/scm/git/git-${GIT_VERSION}.tar.gz -o git.tgz \
  && tar zxf git.tgz \
  && cd git-${GIT_VERSION} \
  && ./configure --prefix=/usr \
  && make \
  && make install \
  && cd / \
  && apt-key adv --keyserver keyserver.ubuntu.com --recv-keys ${DOCKER_KEY} \
  && curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - \
  && [[ $(lsb_release -cs) == "focal" ]] && ( add-apt-repository "deb [arch=$(dpkg --print-architecture)] https://download.docker.com/linux/ubuntu focal stable" ) || ( add-apt-repository "deb [arch=$(dpkg --print-architecture)] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" ) \
  && apt-get update \
  && apt-get install -y docker-ce docker-ce-cli containerd.io --no-install-recommends --allow-unauthenticated \
  && curl -sL "https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose \
  && chmod +x /usr/local/bin/docker-compose \
  && rm -rf /var/lib/apt/lists/* \
  && rm -rf /tmp/*

 

3. unit test 용 base image를 위한 Dockerfile을 작성했다. 이 파일을 Dockerfile.base라고 저장한 경우 아래 커맨드로 docker image를 build 한다. 아래 커맨드는 repo 의 최상단 디렉토리에서 실행한다.

 

# docker build -f {docker file path} -t {docker image name with tag} .
docker build -f Dockerfile.base -t github_action:base .

 

4. 이제 실제로 unit test를 실행하는 Dockerfile을 작성한다.

 

FROM github_action:base

COPY requirements.txt /tmp/ # repo에 종속 라이브러리를 명시한 파일을 복사해옴.
RUN apt-get update &&\
 apt-get -y install # unit test를 위해 설치가 필요한 것들을 여기 적어주자, 없다면 apt-get은 생략
 curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py &&\
 python3 get-pip.py &&\ # 내 경우 pip가 정상작동하지 않는 경우가 있어서 pip만 한번 더 재설치 함
 pip3 install -U pip &&\
 pip3 install --ignore-installed --no-cache-dir -r /tmp/requirements.txt &&\
 rm -rf /var/lib/apt/lists/* /tmp/requirements.txt &&\

ENV AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache
RUN mkdir -p /opt/hostedtoolcache

ARG GH_RUNNER_VERSION="2.277.1"
ARG TARGETPLATFORM

SHELL ["/bin/bash", "-o", "pipefail", "-c"]

WORKDIR /actions-runner
COPY .github/Dockerfiles/install_actions.sh /actions-runner

RUN chmod +x /actions-runner/install_actions.sh \
  && /actions-runner/install_actions.sh ${GH_RUNNER_VERSION} ${TARGETPLATFORM} \
  && rm /actions-runner/install_actions.sh

COPY .github/Dockerfiles/token.sh /
RUN chmod +x /token.sh

COPY .github/Dockerfiles/entrypoint.sh /
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

 

5. 위 파일에서 .github/Dockerfiles/ 밑에 있는 "token.sh", "entrypoint.sh", "install_actions.sh" 파일들을 언급하고 있는데,

https://github.com/myoung34/docker-github-actions-runner

 

myoung34/docker-github-actions-runner

This will run the new self-hosted github actions runners with docker-in-docker - myoung34/docker-github-actions-runner

github.com

여기서 같은 이름의 파일을 찾아서 그대로 복사 붙여넣기하여 repo의 .github/Dockerfiles/ 밑에 작성 후 저장한다. 내 경우는 entrypoint.sh 만 일부 수정해서 사용함.

 

# entrypoint.sh

#!/usr/bin/dumb-init /bin/bash

export RUNNER_ALLOW_RUNASROOT=1
export PATH=$PATH:/actions-runner

deregister_runner() {
  echo "Caught SIGTERM. Deregistering runner"
  _TOKEN=$(bash /token.sh)
  RUNNER_TOKEN=$(echo "${_TOKEN}" | jq -r .token)
  ./config.sh remove --token "${RUNNER_TOKEN}"
  exit
}

_RUNNER_NAME=${RUNNER_NAME:-${RUNNER_NAME_PREFIX:-github-runner}-$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo '')}
_RUNNER_WORKDIR=${RUNNER_WORKDIR:-/_work}
_LABELS=${LABELS:-default}
_RUNNER_GROUP=${RUNNER_GROUP:-Default}
_SHORT_URL=${REPO_URL}
_GITHUB_HOST=${GITHUB_HOST:="github.com"}

if [[ ${ORG_RUNNER} == "true" ]]; then
  _SHORT_URL="https://${_GITHUB_HOST}/${ORG_NAME}"
fi

if [[ -n "${ACCESS_TOKEN}" ]]; then
  _TOKEN=$(bash /token.sh)
  RUNNER_TOKEN=$(echo "${_TOKEN}" | jq -r .token)
  _SHORT_URL=$(echo "${_TOKEN}" | jq -r .short_url)
fi

echo "Configuring"
./config.sh \
    --url "${_SHORT_URL}" \
    --token "${RUNNER_TOKEN}" \
    --name "${_RUNNER_NAME}" \
    --work "${_RUNNER_WORKDIR}" \
    --labels "${_LABELS}" \
    --runnergroup "${_RUNNER_GROUP}" \
    --unattended \
    --replace

unset RUNNER_TOKEN
trap deregister_runner SIGINT SIGQUIT SIGTERM

./bin/runsvc.sh

 

6. github token 만들기

깃헙 계정의 settings → Developer settings → personal access tokens 에서 "workflow" 에 체크 후 생성 -> 생성된 키를 복사

 

7. self hosted runner 가 실행될 서버에서 docker container를 아래 커맨드로 띄운다. 이때 6번에서 복사해둔 키를 ACCESS_TOKEN에 입력해서 사용한다.

 

docker run --gpus 0 -e NVIDIA_VISIBLE_DEVICES=1 -d --restart always --name github-runner \
  -e RUNNER_NAME="myrunner" \
  -e REPO_URL="{your github repo url}"
  -e ACCESS_TOKEN="{your github token}" \
  -e RUNNER_WORKDIR="/tmp/{repo name}" \
  -e RUNNER_GROUP="my-group" \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /tmp/{repo name}:/tmp/{repo name} \
  {docker image name}

끝.

공유하기

facebook twitter kakaoTalk kakaostory naver band
loading