yum 특정 버전으로 설치 또는 업데이트 하기

기본 명령어

# yum [options] COMMAND

# yum list [package name] --showduplicates
# yum install [package name]-[version]
# yum update [package name]-[version]

예제

# yum list kubelet --showduplicates
# yum install kubelet-1.11.3-0
# yum update kubelet-1.11.3-0

주요 명령어 옵션

–enablerepo=[repo] : 여러개의 저장소가 있을 경우, 사용할 저장소를 지정한다.

–disablerepo=[repo] : 사용하지 않을 저장소를 지정한다.

–nogpgcheck : GPG 서명 검증을 사용하지 않는다.

-d [debug level] : 디버깅 레벨을 지정한다. 0-10까지 가능하며, 숫자가 클수록 상세한 정보를 출력한다.

-y, –assumeyes : yum 실행 중에 나오는 질문들을 모두 yes로 처리한다.

MathJax로 수학식 표현하기

MathJax를 사용하면, 수학식을 표현할 수 있습니다. 물론 Jekyll에서 에서도 사용이 가능합니다.

Jekyll에 MathJax 적용하기

mathjax_support.html 파일 생성하기

_includes/mathjax_support.html 파일을 생성 후 아래 내용 입력합니다.

<script type="text/x-mathjax-config">
MathJax.Hub.Config({
    TeX: {
      equationNumbers: {
        autoNumber: "AMS"
      }
    },
    tex2jax: {
    inlineMath: [ ['$', '$'] ],
    displayMath: [ ['$$', '$$'] ],
    processEscapes: true,
  }
});
MathJax.Hub.Register.MessageHook("Math Processing Error",function (message) {
	  alert("Math Processing Error: "+message[1]);
	});
MathJax.Hub.Register.MessageHook("TeX Jax - parse error",function (message) {
	  alert("Math Processing Error: "+message[1]);
	});
</script>
<script type="text/javascript" async
  src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML">
</script>

레이아웃에 추가하기

_layouts/default.html 파일을 열어서, <head> 태그 아래 부분에 아래 내용을 추가합니다.

<script type="text/x-mathjax-config">
MathJax.Hub.Config({
    TeX: {
      equationNumbers: {
        autoNumber: "AMS"
      }
    },
    tex2jax: {
    inlineMath: [ ['$', '$'] ],
    displayMath: [ ['$$', '$$'] ],
    processEscapes: true,
  }
});
MathJax.Hub.Register.MessageHook("Math Processing Error",function (message) {
	  alert("Math Processing Error: "+message[1]);
	});
MathJax.Hub.Register.MessageHook("TeX Jax - parse error",function (message) {
	  alert("Math Processing Error: "+message[1]);
	});
</script>
<script type="text/javascript" async
        src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML">
</script>

MathJax 사용하기

수학식을 표현할 포스트의 앞 부분에 mathjax: true 를 추가합니다.

---
title: "MathJax로 수학식 표현하기"
tags:
  - MathJax
  - Jekyll
mathjax: true
---

MathJax를 이용한 수학 표현 예제

$...$를 이용한 인라인 수식 표현

This formula $f(x) = x^2$ is an example.

This formula $f(x) = x^2$ is an example.

$$...$$를 이용한 블럭 수식 표현

$$
\begin{align*}
P(Y=1|X=\overrightarrow { x } )=&{ \beta  }_{ 0 }+{ \beta  }_{ 1 }{ x }_{ 1 }+{ \beta  }_{ 2 }{ x }_{ 2 }+...+{ \beta  }_{ p }{ x }_{ p }\\=&{ \overrightarrow { \beta  }  }^{ T }\overrightarrow { x }
\end{align*}
$$

$$ \begin{align*} P(Y=1|X=\overrightarrow { x } )=&{ \beta }_{ 0 }+{ \beta }_{ 1 }{ x }_{ 1 }+{ \beta }_{ 2 }{ x }_{ 2 }+…+{ \beta }_{ p }{ x }_{ p }\\=&{ \overrightarrow { \beta } }^{ T }\overrightarrow { x } \end{align*} $$

참고 문서

  • https://ko.wikipedia.org/wiki/위키백과:TeX_문법

kubeadm : unable to select an IP from default routes

상황

쿠버네티스 1.13 버전을 kubeadm을 이용해서 설치하려고 했으나, IP를 찾을 수 없어서 에러가 발생하였습니다.

$ kubeadm init --config=kubeadm-config.yaml
unable to select an IP from default routes.
 
$ kubeadm init --config=kubeadm-config.yaml --v 10
I0114 20:04:41.384877 49609 interface.go:384] Looking for default routes with IPv4 addresses
I0114 20:04:41.384895 49609 interface.go:389] Default route transits interface "eth0.100"
I0114 20:04:41.386764 49609 interface.go:196] Interface eth0.100 is up
I0114 20:04:41.386833 49609 interface.go:244] Interface "eth0.100" has 1 addresses :[fe80::e642:4bff:fe1f:28b0/64].
I0114 20:04:41.386857 49609 interface.go:211] Checking addr fe80::e642:4bff:fe1f:28b0/64.
I0114 20:04:41.386873 49609 interface.go:224] fe80::e642:4bff:fe1f:28b0 is not an IPv4 address
I0114 20:04:41.386892 49609 interface.go:384] Looking for default routes with IPv6 addresses
I0114 20:04:41.386903 49609 interface.go:389] Default route transits interface "eth1.100"
I0114 20:04:41.389546 49609 interface.go:196] Interface eth0.100 is up
I0114 20:04:41.389592 49609 interface.go:244] Interface "eth0.100" has 1 addresses :[fe80::e642:4bff:fe1f:28b0/64].
I0114 20:04:41.389608 49609 interface.go:211] Checking addr fe80::e642:4bff:fe1f:28b0/64.
I0114 20:04:41.389622 49609 interface.go:221] Non-global unicast address found fe80::e643:4bff:fe1f:38b0
I0114 20:04:41.389634 49609 interface.go:400] No active IP found by looking at default routes
unable to fetch the kubeadm-config ConfigMap: unable to select an IP from default routes.

네트워크 인터페이스(network interface)에서 IP를 찾을 수 없기 때문에 발생하는 에러였습니다. 해당 서버는 loopback 인터페이스에 IP가 바인딩 되어 있었는데, kubeadm이 사용하는 코드에서는 loopback 인터페이스를 확인하지 않았습니다. 아마 IPv4 BGP over IPv6 (rfc5549)을 사용한거 같은데, 자세한 사항은 모르겠습니다.

이 문제에 대한 이슈는 등록되어 있고, 해결 방법으로 PR이 올라가 있지만 반영되지 않았습니다.

이 문제를 해결하기 위한 방법은, 네트워커 설정을 변경하거나, kubeam 코드를 패치하면 됩니다. 이 문서에는 간단히 kubeam 코드 패치를 선탁하였습니다.

kubeadm 빌드하기

소스 코드 빌드 과정은 Docker 컨테이너 안에서 일어나기 때문에, 별도의 golang 환경을 구축할 필요는 없습니다.

kubeadm 빌드하는 과정은 간단합니다.

우선 쿠버네티스 소스를 받습니다.

git clone https://github.com/kubernetes/kubernetes.git
cd kubernetes

태그로 버전을 확인한 후, 본인이 원하는 버전으로 체크아웃 합니다.

git tag
git checkout v1.13.6

staging/src/k8s.io/apimachinery/pkg/util/net/interface.go 파일을 열어서, 아래와 같은 코드를 추가해 줍니다. (https://github.com/kubernetes/kubernetes/pull/69578/files 을 참고하시기 바랍니다.)

			klog.V(4).Infof("Default route exists for IPv%d, however interface %q does not have global unicast addresses. Checking loopback interface", uint(family), route.Interface)
			loopbackIP, err := getIPFromInterface("lo", family, nw)
			if err != nil {
				return nil, err
			}
			if loopbackIP != nil {
				klog.V(4).Infof("Found active IP %v on loopback interface", loopbackIP)
				return loopbackIP, nil
			}

빌드 스크립트를 실행서, kubeadm을 빌드합니다.

build/run.sh make kubeadm KUBE_BUILD_PLATFORMS=linux/amd64

빌드가 정상적으로 끝나면, _output/dockerized/bin/linux/amd64/kubeadm 에 파일을 생성합니다.

생성한 파일을 서버로 이동해서, 설치하시면 됩니다.

다른 방법

특정 NIC에 아이피를 직접 할당해 줍니다.

- name: check if we need to re-assign ip
  shell: |
    if ip addr show eth0.100 > /dev/null; then
      ip addr show eth0.100 | grep 'inet ' > /dev/null;
    else
      true;
    fi;
  # need_to_reassign.rc = 0
  #  => not need to reassign
  # need_to_reassign.rc = 1
  #  => need to reassign
  register: need_to_reassign
  changed_when: False
  ignore_errors: True
   
- name: re-assing ip onto ethX.100
  shell: |
    private_ip=$(/sbin/ip a show dev private | grep 'inet '  | awk '{print $2}') && /sbin/ip addr add ${private_ip} dev eth0.100 && /sbin/ip addr add ${private_ip} dev eth1.100
  when: need_to_reassign.rc != 0

참고 문서

  • https://github.com/kubernetes/kubeadm/issues/1156
  • https://github.com/kubernetes/kubernetes/pull/69578
  • https://kubernetes.io/docs/setup/release/building-from-source/
  • https://github.com/kubernetes/kubernetes/tree/master/build/

Go Modules

Go 언어의 초창기에는 의존성 관리를 위한 마땅한 도구가 없었습니다. 하지만 프로젝트를 진행함에 있어 의존성 관리는 꼭 필요한 기능입니다. 그래서, 시간이 지남에 따라 다양한 써드파트 도구가 등장하기 시작했습니다. 대표적으로 vgodepglide 등이 있습니다. 이렇게 표준이 없어서, 여러 써드파트 도구가 사용되다가, Russ Cox의 제안으로 vgo 프로젝트가 Go의 공식툴로 채택되었고, go 1.11 버전에서 Go Modules가 도입되어 사용할 수 있게 되었습니다. (GOPATH 안녕~~~)

GO111MODULE

go 1.11 버전에 Go Modules이 등장하면서, 기존 버전에서 사용하는 환경과 공종을 하기 위해서 GO111MODULE 이라는 환경변수가 생겼습니다. 이 환경변수에는 세 가지의 값이 올 수 있습니다.

GO111MODULE의 값이 on인 경우에는 go 명령어는 GOPATH에 상관없이 Go Modules의 방식으로 작동합니다. off인 경우에는 반대로, Go Modules을 비활성화하고 기존에 사용하던 방식인 GOPATH를 이용합니다. 그리고 값이 없거나 auto인 경우에는 GOPATH 내부에서는 기존 방식대로, 외부에서는 Go Modules 방식대로 작동합니다.

명령어

go mod init : 모듈을 생성합니다.

go get @ : 특정 버전을 지정해서 모듈을 추가합니다.

go mod tidy [-v] : go.mod 파일가 소스 파일을 비교하여, import 하지 않은 모듈은 제거하고 import 하였지만 의존성 목록에 추가되지 않은 모듈은 추가합니다.

go mod vendor : vendor 디렉토리를 생성하고, 모듈들을 복사합니다.

go mod verify : 모듈의 유효성을 검증합니다.

ceph rbd 이미지 삭제하기

상황

ceph의 물리적 저장 용량이 부족해서, 쿠버네티스의 PV를 삭제하였습니다. PV 를 삭제하면 용량을 확보할 수 있을 줄 알았는데, 그렇지 않았습니다. (PV의 설정을 잘못한건가???)

PV는 삭제되었지만, ceph에는 그대로 파일들이 남아있었습니다. 그래서 수작업으로 파일들을 삭제하였습니다.

작업 로그

용량 보기

$ ceph osd lspools
0 rbd,1 kube-xxx,2 kube-yyy,3 kube-zzz,

$ rados df
pool name KB objects clones degraded unfound rd rd KB wr wr KB
kube-xxx 203236277 50236 0 0 0 2656421 182868220 147679538 5831075965
kube-yyy 0 0 0 0 0 0 0 0 0
kube-zzz 181152993 44417 0 0 0 19325662 908304090 32869011 5467331110
rbd 0 0 0 0 0 0 0 0 0
total used 1212089217 94653
total avail 1112637423
total space 2324726640

rbd 이미지 목록 보기

$ rbd list -p kube-zzz

kubernetes-dynamic-pvc-234b756d-25e7-11e9-b73c-0a580af40203
kubernetes-dynamic-pvc-3782458d-64d0-11e9-b73c-0a580af40203
kubernetes-dynamic-pvc-49fd82c0-6635-11e9-b73c-0a580af40203
kubernetes-dynamic-pvc-615d1d51-25e7-11e9-b73c-0a580af40203
kubernetes-dynamic-pvc-a62f7ee0-56b2-11e9-b73c-0a580af40203
kubernetes-dynamic-pvc-cb7d70f3-4081-11e9-b73c-0a580af40203

rbd 이미지 삭제 하기

$ rbd -p kube-zzz status kubernetes-dynamic-pvc-cb7d70f3-4081-11e9-b73c-0a580af40203
Watchers: none

$ rbd -p kube-zzz rm kubernetes-dynamic-pvc-cb7d70f3-4081-11e9-b73c-0a580af40203
Removing image: 100% complete...done.

참고 문서

Kubernetes 에서 NVIDIA GPU container 사용하기

기본적인 docker를 이용하면, GPU 자원을 사용할 수 없습니다. 쿠버네티스 환경에서 NVIDIA GPU를 사용하기 위해서는 nvidia-docker를 이용해야 합니다.

nvidia-docker 설치하기

nvidia-smi

repository 추가

드라이버가 설치되어 있다면, nvidia-docker 설치를 위한 repository를 추가해 줍니다.

Debian-based distributions

curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | \
  sudo apt-key add -
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | \
  sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update

RHEL-based distributions

distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.repo | \
  sudo tee /etc/yum.repos.d/nvidia-docker.repo

nvidia-docker 설치

Debian-based distributions

sudo apt-get install -y nvidia-docker2
sudo pkill -SIGHUP dockerd

RHEL-based distributions

sudo yum install -y nvidia-docker2
sudo pkill -SIGHUP dockerd

nvidia-docker 확인

설치가 끌나면, 아래처럼 --runtime=nvidia 플래그를 이용해서 GPU를 사용할 수 있습니다. 아래 명령어를 실행하면 GPU를 사용할 수 있는 상태인지 확인할 수 있습니다.

$ docker run --runtime=nvidia --rm nvidia/cuda nvidia-smi
Mon Jul 15 12:45:56 2019
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 418.67       Driver Version: 418.67       CUDA Version: 10.1     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla M40           Off  | 00000000:02:00.0 Off |                    0 |
| N/A   35C    P0    63W / 250W |    115MiB / 11448MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   1  Tesla M40           Off  | 00000000:82:00.0 Off |                    0 |
| N/A   26C    P8    16W / 250W |      0MiB / 11448MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   2  Tesla M40           Off  | 00000000:85:00.0 Off |                    0 |
| N/A   24C    P8    16W / 250W |      0MiB / 11448MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   3  Tesla M40           Off  | 00000000:86:00.0 Off |                    0 |
| N/A   24C    P8    16W / 250W |     11MiB / 11448MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0     21141      C   python                                       104MiB |
+-----------------------------------------------------------------------------+

쿠버네티스에서 nvidia-docker 사용하기

쿠버네티스 환경에서 nvidia-docker를 사용하려면, docker의 기본 런타임(runtime)을 변경하고, NVIDIA 디바이스 플러그인을 설치해줘야 합니다.

docker 기본 runtime 변경

정상적으로 nvidia-docker2가 설치되었다면, /etc/docker/daemon.json 파일이 생성되었을 것입니다. 해당 파일을 열여서 "default-runtime": "nvidia"을 추가해주면 됩니다.

{
  "default-runtime": "nvidia", 
  "runtimes": {
    "nvidia": {
      "path": "nvidia-container-runtime",
      "runtimeArgs": []
    }
  }
}

파일을 수정한 후, docker daemon을 재시작 하여야합니다.

sudo systemctl restart docker

kubernetes-device-plugin 설치

kubectl을 이용해서 nvidia-device-plugin을 설치해 줍니다.

kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v1.11/nvidia-device-plugin.yml

참고) nvidia-device-plugin.yml

apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: nvidia-device-plugin-daemonset
  namespace: kube-system
spec:
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      # Mark this pod as a critical add-on; when enabled, the critical add-on scheduler
      # reserves resources for critical add-on pods so that they can be rescheduled after
      # a failure.  This annotation works in tandem with the toleration below.
      annotations:
        scheduler.alpha.kubernetes.io/critical-pod: ""
      labels:
        name: nvidia-device-plugin-ds
    spec:
      tolerations:
      # Allow this pod to be rescheduled while the node is in "critical add-ons only" mode.
      # This, along with the annotation above marks this pod as a critical add-on.
      - key: CriticalAddonsOnly
        operator: Exists
      - key: nvidia.com/gpu
        operator: Exists
        effect: NoSchedule
      containers:
      - image: nvidia/k8s-device-plugin:1.11
        name: nvidia-device-plugin-ctr
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: ["ALL"]
        volumeMounts:
          - name: device-plugin
            mountPath: /var/lib/kubelet/device-plugins
      volumes:
        - name: device-plugin
          hostPath:
            path: /var/lib/kubelet/device-plugins

참고 : Feature Gates

nvidia-device-plugin을 사용하려면, 해당 노드 kubelet의 DevicePlugins이 “true”로 설정되어 있어야한다. 쿠버네티스 1.10 이상에서는 기본값이 “true”이기 때문에 별도의 설정이 필요없으나, 혹시라도 1.8이나 1.9를 사용한다면, KUBELET_EXTRA_ARGS=--feature-gates=DevicePlugins=true 로 값을 설정해주어야한다.

  • https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/

GPU 자원(Resource) 이용

GPU 자원을 이용하려면, 리소스 요구사항에 nvidia.com/gpu을 사용하면 됩니다.

apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  containers:
    - name: cuda-container
      image: nvidia/cuda:9.0-devel
      resources:
        limits:
          nvidia.com/gpu: 1 # requesting 1 GPUs

참고 문서

docker 명령어

도커 이미지 관련 명령어

docker login [repository] : 저장소(repository)에 로그인한다. 저장소 주소를 적지 않으면 Docker Hub repository 로 로그인한다.

docker create [image] : 해당 이미지로부터 새로운 컨테이너를 생성한다.

docker pull [image] : 이미지를 저장소로부터 가져온다.

docker push [image] : 이미지를 저장소에 올린다.

docker tag [source] [target] : 원본 이미지 새로운 태그를 부여한다.

docker search [term] : 해당 단어로 저장소에 있는 이미지를 검색한다.

docker images : 로컬 시스템에 저장되어 있는 이미지 목록을 보여준다.

docker history [image] : 해당 이미지의 히스토리를 보여준다.

도커 컨테이너 관련 명령어

docker ps : 현재 실행중인 컨테이너 목록을 보여준다.

docker run [image] : 해당 이미지로 도커 컨테이너를 실행한다.

docker start [container] : 도커 컨테이너를 시작한다.

docker stop [container] : 도커 컨테이너를 중지한다. (SIGTERM -> SIGKILL)

docker stop $(docker ps -q) : 현재 작동하는 모든 도커 컨테이너를 중지한다.

docker kill [container] : 도커 컨테이너를 강제로 중지한다. (SIGKILL)

docker inspect [container] : 컨테이너의 상세 정보를 보여준다.

docker rm [container] : 중지된 도커 컨테이너를 삭제한다.

docker rm $(docker ps -a -q) : 중지된 모든 도커 컨테이너를 삭제한다.

docker exec -it [container] [command] : 대상 도커 컨테이너에 명령어를 실행한다.

기타 명령어

docker info : 도커 상세 정보를 보여준다.

docker version : 도커 버전을 보여준다.

docker stats : 현재 도커 컨테이너들의 상태로 보여준다.

Ingress nginx 파일 업로드 크기 제한 늘리기

Ingress NginX : Custom max body size

ingress-nginx를 사용하는 중, 파일 업로드 중 413 에러가 발생하였습니다. 이 경우는 nginx가 허용하는 것보다, 큰 파일이 업로드 되어 에러가 발생한 것이었습니다.

허용하는 최대 파일 크기를 늘리는 방법은 두 가지가 있습니다.
첫번째는 configmap을 에 설정하는 것이고, 두번째는 ingress 에 커스텀 어노테이션을 추가하는 것입니다. configmap에 설정할 경우는 글로벌하게 적용되고, 커스텀 어노테이션을 사용할 경우는 해당 ingress만 영향을 받습니다.

ConfigMap

nginx-configuration 이름의 nginx configmap에 proxy-body-size 값을 설정합니다.

apiVersion: v1
data:
  proxy-body-size: "1024m"
kind: ConfigMap
metadata:
labels:
  app: ingress-nginx
name: nginx-configuration

Ingress annotation

Ingress 리소스에 아래와 같이 어노테이션을 추가하면 됩니다.

nginx.ingress.kubernetes.io/proxy-body-size: 10m\
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: 1024m
  labels:
    app: kubeflow
  name: kubeflow
  namespace: kubeflow
spec:
  rules:
  - host: kubeflow.xxx.yyy
    http:
      paths:
      - backend:
          serviceName: ambassador
          servicePort: 79
        path: /

참고 문서

Docker 로그 관리

도커(docker)는 로깅 드라이버(logging driver) 통해, 로그를 남기게 되어 있습니다. 로깅 드라이버의 기본 값을 json-file입니다. 즉, 로그를 json 형식으로 파일로 저장하게 됩니다.

아래 명령어를 실행하면, 해당 도커의 로깅 드라이버가 뭔지 알 수 있습니다.

$ docker info --format ''
json-file

json-file 로깅 드라이버를 사용하는 경우, 시간이 지날 수록 로그 파일이 쌓이기 때문에 주기적으로 파일을 삭제해줘야합니다. 주기적으로 파일을 삭제하는 방법은, 도커 데몬의 설정을 변경하거나, logrotate를 이용하는 것입니다.

도커 데몬 설정 파일 변경하기

/etc/docker/ 디렉토리에 있는 daemon.json 파일에 아래와 같은 내용을 추가해 주면 됩니다.

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3" 
  }
}

도커 재시작하면 변경 사항이 반영됩니다.

logrotate 이용하기

logrotate는 로그를 관리하기 위해 사용되는 범용툴입니다. 서버에 설치가 안되어 있다면, 설치가 필요합니다. 아래와 같이 컨테이너 로그를 정리하는 설정 파일을 추가해 주면 됩니다.

cat > /etc/logrotate.d/container << EOF
/var/lib/docker/containers/*/*.log {
    rotate 100
    copytruncate
    missingok
    notifempty
    compress
    maxsize 100M
    maxage 30
    daily
    dateext
    dateformat -%Y%m%d-%s
    create 0644 root root
}
EOF

참고 문서

Spring Boot 시작시 /dev/./urandom을 사용하는 이유

SpringBoot 실행 예제를 보면 -Djava.security.egd=file:/dev/./urandom 플래그를 간혹 볼 수 있습니다. 이 플래그가 왜 필요한지에 대해서 간단히 설명해 보겠습니다.
스프링 부트를 이용해서 웹 애플리케이션을 만들 때, 기본적으로 톰캣을 이용하게 됩니다. 이 톰캣은 자바의 SecureRandom 클래스를 사용해서, 세션 아이디 같은 것을 생성하게 됩니다. 리눅스(linux) 환경의 경우, SecureRandom 클래스는 안전한 난수 생성을 위해서 /dev/random을 사용합니다.
리눅스에서는 /dev/random과 /dev/urandom이라는 두 개를 난수발생기(PRNG : pseudo-randum number generator)를 제공 합니다. 이 난수 발생기는 디바이스 드라버에서 발생하는 입력 신호 등을 이용해서 난수를 발생시킵니다. 즉, 키보드나 마우스 클릭 같은 디바이스의 입줄력 신호를 엔트로피 풀(Entropy pool)에 저장하고, 난수를 생성할때 엔트로피 풀에서 필요한 크기 만큼 가져다 사용하게 됩니다.
문제는 이 엔트로피 풀에 저장되어 있는 데이터가 부족할 때 발생합니다. /dev/random 경우 엔트로피 풀에 필요한 크기 만큼의 데이터가 부족할 경우, 블록킹(blocking) 상태로 대기하게 됩니다. 이런 경우 애플리케이션이 행(hang)에 걸린것 처럼 멈처버리는 현상이 발생합니다. 이 문제를 해결하기 위해서 /dev/urandom을 사용한 것입니다. /dev/urandom 같은 경우에는 엔트로피 풀에 있는 데이터가 충분하지 않아도, 난수를 생성해버립니다. (하지만 /dev/random에 비해서는 난수의 무작위성이 떨어집니다.) 그래서 난수로 인한 애플리케이션의 블록킹 사태를 막기 위해서 /dev/urandom를 사용하기도 합니다.
그런데 여기서 한가지 의문 사항이 드는데, 왜 /dev/urandom이 아니라 /dev/./urandom을 사용했을까요? 그 이유는 자바 버그로 인해서 입니다. Java5 이휴의 특정 버전에서는 /dev/urandom을 설정하면, /dev/random로 인식해 버리는 버그가 있습니다.