Information Security Study
240202 도커(컨테이너 상태 감지, inspect로 내부 구조 확인, cp로 호스트파일 복사, events, kill) 본문
240202 도커(컨테이너 상태 감지, inspect로 내부 구조 확인, cp로 호스트파일 복사, events, kill)
gayeon_ 2024. 2. 2. 16:53모니터링용 이미지 및 컨테이너로 상태 감시하기
docker stats로도 상태를 감시할 수는 있지만
그보다 좀 더 전문적으로 감시할 수 있는 툴이 존재한다.
cadvisor라는 이미지와 컨테이너를 이용하면 된다.
도커허브가 아닌 gcr에 올라와있는 이 이미지는 아래와 같이 복잡한 명령어로
볼륨마운트를 해야만 볼 수 있다.
$ docker run \\
--restart=always \\
--volume=/:/rootfs:ro \\
--volume=/var/run:/var/run:rw \\
--volume=/sys/fs/cgroup:/sys/fs/cgroup:ro \\
--volume=/var/lib/docker/:/var/lib/docker:ro \\
--volume=/dev/disk/:/dev/disk:ro \\
--publish=8765:8080 \\
--detach=true \\
--name=cadvisor \\
--privileged \\
--device=/dev/kmsg \\
gcr.io/cadvisor/cadvisor:latest
ip:8765로 접속하면 위와 같이 컨테이너 상태를 확인할 수 있다.
이제 cadvisor 컨테이너를 먼저 조회해보고 다음으로 브라우저에서 접속할 것이다.
그러면 메트릭 형태로 실시간 트래픽을 보여주게 된다.
다음으로 리눅스에서 반복문을 수행시키면 헬스체크를 수행하도록 할 수도 있다.
헬스체크란 서버의 가동 여부를 지속적으로 확인하는 행위이다.
$ while true; do curl node서버주소; sleep 초단위; done
sleep으로 딜레이를 주기 때문에 몇 초 마다 한번씩 node서버에 접속하게 된다.
해당 명령어로 nodeapp에 지속적으로 요청을 넣어 찍히는 log를 확인한다.
console.log()로 찍히는 명령어를 확인한다.
$ docker logs -f 컨테이너명
원래 log 관련된 내용은
$ docker info | grep -i log
로 조회시 json 파일로 저장되는 것을 볼 수 있다.
이 파일이 너무 비대해지면 당연히 디스크가 모자라는 일이 벌어질수도 있다.
특정 컨테이너에서 발생하는 로그는
$ sudo ls -l /var/lib/docker/containers
조회시 이제 컨테이너별로 저장된 로그 내역이 나오게 되고
docker ps로 조회해서 나온 컨테이너 아이디를 포함한 값을 전체적으로 조회할 수 있고
해당 값으로 조회를 하면 된다.
그러면 로그에 대한 json파일을 비롯한 많은 정보 파일들이 보인다.
또한 컨테이너를 띄워놨다면 계속해서 용량이 늘어나는것도 볼 수 있다.
따라서 로그를 백업했다면 비워줄 필요도 있다.
로그를 비우는 명령어는
$ sudo truncate -s 0 /var/lib/docker/contaners/컨테이너아이디-json.log
를 수행하면 된다.
그러면 로그파일이 초기화되어 다시 용량이 0부터 출발한다.
혹은 log파일의 사이즈를 제한할수도 있다.
$ sudo vi /etc/docker/daemon.json
접속 후
{
"insecure-registries": ["아이피주소"],
"log-driver": "json-file",
"log-opts": {
"max-size": "30m",
"max-file": "10"
}
}
위와 같이 로컬 레지스트리 정보와 마찬가지로 나열해주면 된다.
이후
$ sudo systemctl restart docker.service
수행 후
$ sudo systemctl status docker.service
를 이용해서 조회해보면 갱신내역을 확인할 수 있고
아니라면 docker run을 수행할 당시에
$ docker run \\
--log-driver json-file \\
--log-opt max-size=30m \\
--log-opt max-file=10
위 옵션을 같이 포함해서 주면 된다.
위 방식은 그러나 stdout(표준 출력) 만을 반영하는 log 이다.
따라서 에러상황의 로그를 보려면 추가적인 작업이 필요하다.
$ docker run -itd --name=mysql-5 mysql:5.7-debian
위 명령어는 환경변수를 포함하지 않았기 때문에 컨테이너가 뜨자마자 에러로 stop이 된다.
$ docker ps -a | grep mysql
조회시 상태가 Exited인것을 볼 수 있다.
이제
$ docker logs mysql-5
로 조회를 하면 에러메세지가 뜨는것을 볼 수 있다.
에러메세지에서 반드시 넣어줘야 하는 환경변수를 지목하기 때문에 해당 변수를 지정하고
다시 실행해서 정상실행되는것을 확인해주면 된다.
컨테이너 내부 구조 inspect로 확인하기
앞서서 docker image에 대한 inspect를 봤었는데 컨테이너에도 당연히 적용된다.
$ docker container inspect 컨테이너명
inspect 명령어를 씀에 있어서 image가 타겟인지 container가 타겟인지 명시하면 된다.
사실 image나 container는 명칭이 겹치지 않는다면 생략해도 된다.
cp 명령어로 컨테이너 내부로 호스트 파일 복사해서 넘기기
간헐적으로 간단한 파일을 전송해야 할 때는 볼륨마운트 대신 cp로 넘기기도 한다.
$ docker cp 호스트의파일명 컨테이너명:경로와파일명
형식으로 호스트 파일을 컨테이너로 보낼 수 있다.
node같은 경우 /app/app.js 를 전달하면 된다.
파일을 전달한 다음
$ docker restart 컨테이너명
을 이용해 재시작해서 갱신되었는지 여부를 확인할 것이다.
또한 역으로 컨테이너 내부의 파일을 호스트로 가져올 수도 있다.
이 경우는
$ docker cp 컨테이너명:경로와파일명 호스트에서받을파일명
과 같이 파라미터의 순서만 바꿔주면 된다.
예를들어 nginx의 reverse proxy 구성에 대해서
$ docker cp nginx서버명:/etc/nginx/nginx.conf 호스트의경로/nginx.conf
와 같은 형식으로 conf 파일을 뽑아서 가지고 온 다음
리버스 프록시 구성을 마치고 나서 다시 돌려보내기 위해
$ docker cp nginx.conf 컨테이너명:/etc/nginx/nginx.conf
로 돌려놓고
$ docker restart nginx컨테이너명
을 지정하면 된다.
도커 이벤트 활용해 컨테이너 상태 확인해보기
지금까지 3초마다 while문으로 curl을 계속해서 하고 있었다.
이번에는 다른 터미널에서 이벤트 명령을 활용할 것이다.
$ docker events
이벤트는 마지막 1000개의 이벤트를 기록한다.
내부를 보면 $CADIVISOR_HEALTHCHECK_URL 이 보인다.
이를 통해 지속적으로 컨테이너 정보나 메트릭에 대한 통신을 하고 있다는 것을 알 수 있고
nodeapp에 지속적으로 요청을 넣는 반복문을 ctrl + c로 중지시킨다음
$ docker stop nodeapp
으로 nodeapp 컨테이너 자체를 중지시키면
이벤트에서는 container kill 이라는 명령어가 나오는 것을 볼 수 있다.
다시 컨테이너를 start로 기동해보면
$ docker start nodeapp
또 다시 도커 이벤트가 이를 감지해서 출력하는 것을 볼 수 있다.
$ docker pause nodeapp
pause 등의 전반적인 컨테이너 상태의 변경이 유도될 때 마다
그때그때 event가 감지하는것을 볼 수 있다.
또한 pause상태에서는 while문으로 curl을 보내도 아무 반응이 없다.
그리고 pause는 unpause로 풀 수 있다.
$ docker unpause nodeapp
이벤트는
$ docker events --until time(시|분|초)
위와 같이 특정 시분초를 지정해 그때까지만 감시하거나
$ docker events --since date1 date2
위와 같이 특정 날짜의 0시부터 다음 날짜의 0시까지 지정하는 등
위와 같은 형식으로 특정 기간 사이에만 돌리는 것도 가능하다.
또한 특정 이벤트만 집중적으로 감시하기 위해
$ docker events --filter “key=value”
형식을 사용할 수도 있다.
docker에서의 kill 사용
리눅스의 kill은 보통 15번(정상종료) 아니면 9번(강제종료) 를 활용하기 위해 사용한다.
마치 윈도우의 관리자도구처럼 사용되는 것이다.
도커에서도 유사한 docker kill 명령어가 있다.
이를 활용해보기 위해서 먼저 nodeapp 앱의 쉘로 진입할 것이다.
알파인 리눅스이므로 bash 사용이 불가능하다.
$ docker exec -it nodeapp sh
이후
# cat /etc/os-release
입력시 리눅스 버전 확인이 가능하다.
이제 3번째 터미널을 켜서 거기서
$ docker kill nodeapp
을 수행한 다음 이벤트를 확인한다.
nodeapp이 끊어지면서 동시에 알파인 리눅스도 중지되기 때문에
2번 터미널도 그냥 hostos1로 환원되는 것을 볼 수 있다.
이후 3번 터미널에서 ps -a로 조회시 exited(0이아닌번호) 가 나온다.
0번의 경우 자연적으로 종료된 케이스
137번의 경우 kill명령어로 강제종료한 케이스 등이다.
다만 도커의 kill은 컨테이너를 죽이지만
리눅스의 kill로죽이는 케이스는 컨테이너의 완전 종료로 간주하지 않기 때문에
딱히 세션이 끊어지지 않는 것을 볼 수 있다.
다시 컨테이너 실행 후 쉘에 들어갔다.
확인하면 host에서 돌고 있다고 조회된다.
kill pid로 강제종료가 가능하다.
그러면 쉘도 강제종료된다.
그런데 docker ps 해보면 nodeapp이 돌고 있다고 나온다.
따라서 리눅스의 kill은 사용하지 않는 게 좋다.