Skip to content

Instantly share code, notes, and snippets.

@leoh0
Last active December 1, 2021 00:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leoh0/4828213eb654a8b1b7ce60e87960e806 to your computer and use it in GitHub Desktop.
Save leoh0/4828213eb654a8b1b7ce60e87960e806 to your computer and use it in GitHub Desktop.
컨테이너 안에서 호스트를 향한 시스템이벤트를 가로채서 원하는 결과값 주기

Hijacking sysconf cpu count in container

문제

nginx에서는 worker_processes의 개수를 auto로 주어질시 sysconf 를 통해 host의 cpu값을 얻어오고 있습니다. 코드 참고

image

하지만 container 안에서는 보통 아래의 값들을 참고해서 cpu 값을 부여하고 있습니다.

  • cpu share

    • /sys/fs/cgroup/cpu/cpu.shares
  • cpuset

    • /sys/fs/cgroup/cpuset/cpuset.cpus
  • cpu-period

    • /sys/fs/cgroup/cpu/cpu.cfs_period_us
  • cpu-quota

    • /sys/fs/cgroup/cpu/cpu.cfs_quota_us

특히 k8s 에서 부여되는 resource limit 같은 경우는 위에서 cpu share 값을 이용하고 있습니다.

그래서 nginx를 worker_processes 옵션을 auto로 주고 k8s에서 limit 를 줄시에도 host cpu 개수 만큼 worker process 들이 뜨게 되는 문제가 있습니다.

만약 이 옵션을 컨테이너에서 사용하려면 어떻게 하면 될까요?

LD_PRELOAD를 이용하면 지정한 라이브러리가 동적인 링킹을 할때 먼저 참조되도록 하는 방법을 사용할 수 있습니다.

그래서 이방법을 이용시 sysconf 함수를 하이재킹해서 결과값을 원하는 값으로 집어 넣는 방법을 사용할 수 있습니다.

이 부분중 sysconf_SC_NPROCESSORS_ONLN 를 참조하는 부분을 미리 작성한 라이브러리가 있습니다.

http://www.kev.pulo.com.au/libsysconfcpus/

즉, 이 라이브러리를 LD_PRELOAD로 지정시 먼저 로딩되어 sysconf 함수를 원하는 목적으로 바꿀 수 있게 됩니다.

사용법

적당히 위 dockerfile을 빌드하고 사용하면 됩니다. 저도 k8s에서 테스트를 안해봤는데 hack.sh 에 내용을 적당히 바꿔서 하시면 됩니다.

우선 k8s에서는 cpu share을 사용하고 다른 컨테이너는 위의 4가지 옵션중 조정해서 사용하기 때문에 각각 목적에 맞게 hack.sh을 변경해서 사용하면 됩니다.

참고

FROM alpine/git as git
WORKDIR /
RUN git clone https://github.com/obmarg/libsysconfcpus.git
FROM gcc as builder
COPY --from=git /libsysconfcpus /libsysconfcpus
RUN /libsysconfcpus/configure && make && make install
FROM nginx:alpine
COPY --from=builder /usr/local/lib/libsysconfcpus.so /usr/local/lib/
COPY hack.sh /
ENV LD_PRELOAD="/usr/local/lib/libsysconfcpus.so"
ENTRYPOINT [ "sh", "/hack.sh", "nginx", "-g", "daemon off;" ]
#!/bin/sh
export LIBSYSCONFCPUS=$(($(cat /sys/fs/cgroup/cpu/cpu.shares) / 1024))
exec "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment