컨테이너에 접속해서 무언가 보려는 것이 목적이라면 SSH 서버를 넣을 이유가 없다. docker exec 로 충분하고, 이쪽이 계정·비밀번호·키를 관리할 필요가 없어 훨씬 안전하다.
docker exec -it myapp /bin/bash
docker logs -f myapp
docker cp myapp:/var/log/app.log ./
SSH 서버를 굳이 넣는 것은 외부 도구가 SSH 로만 붙을 수 있는 경우 정도다. 이때도 컨테이너는 "한 프로세스" 라는 전제가 깨지므로, 재시작·로그 수집·상태 판정이 모두 번거로워진다는 점을 감수해야 한다.
FROM httpd:2.4
RUN apt-get update \
&& apt-get install -y --no-install-recommends openssh-server \
&& rm -rf /var/lib/apt/lists/* \
&& mkdir -p /var/run/sshd
RUN useradd -ms /bin/bash appops \
&& mkdir -p /home/appops/.ssh \
&& chmod 700 /home/appops/.ssh
COPY authorized_keys /home/appops/.ssh/authorized_keys
RUN chown -R appops:appops /home/appops/.ssh \
&& chmod 600 /home/appops/.ssh/authorized_keys
EXPOSE 22 80
지켜야 할 것이 몇 가지 있다.
비밀번호를 Dockerfile 에 쓰지 않는다. RUN echo 'user:password' | chpasswd 같은 줄은 이미지 레이어에 평문으로 남고, 이미지를 받은 누구나 읽을 수 있다. 공개 키를 넣고 PasswordAuthentication no 로 둔다.
root 로그인을 열지 않는다. PermitRootLogin no 가 기본값이다. 굳이 바꾸지 않는다.
호스트 키를 이미지에 굽지 않는다. 이미지에 구운 호스트 키는 그 이미지를 쓰는 모든 컨테이너가 공유하게 된다. 기동 시점에 생성하거나 볼륨으로 주입한다.
컨테이너는 PID 1 하나를 감시한다. SSH 와 애플리케이션을 함께 띄우려면 앞단에 관리 프로세스가 필요하다. service ... start 를 나열하고 tail -f /dev/null 로 붙잡아 두는 스크립트가 흔히 돌아다니지만, 이 방식은 자식 프로세스가 죽어도 컨테이너가 살아 있는 것처럼 보인다. 장애를 못 잡는다는 뜻이다.
권장 순서는 이렇다.
첫째, 서비스를 컨테이너마다 하나씩 쪼갠다. MariaDB 와 웹 서버를 한 이미지에 넣는 대신 Compose 로 두 서비스를 띄우고 네트워크로 잇는다. 상태를 가지는 데이터베이스는 볼륨을 붙인다.
services:
db:
image: mariadb:11
environment:
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
volumes:
- dbdata:/var/lib/mysql
web:
image: myapp
depends_on:
- db
ports:
- "8080:8080"
volumes:
dbdata:
둘째, 도저히 한 컨테이너에 넣어야 한다면 supervisord 나 s6-overlay 같은 프로세스 관리자를 PID 1 로 둔다. 자식이 죽으면 다시 띄우거나 컨테이너를 종료시키므로, 오케스트레이터가 이상을 감지할 수 있다.
docker run -d --name myapp --restart unless-stopped -p 8080:8080 myapp:latest
| 값 | 동작 |
|---|---|
no |
기본값. 재시작하지 않는다 |
on-failure[:N] |
비정상 종료일 때만. 횟수 제한 가능 |
unless-stopped |
항상. 단 사람이 명시적으로 멈춘 것은 재부팅 후에도 그대로 둔다 |
always |
항상. 사람이 멈춘 것도 데몬 재시작 시 다시 뜬다 |
이미 돌고 있는 컨테이너의 정책은 나중에 바꿀 수 있다.
docker update --restart unless-stopped myapp
호스트 부팅 시 자동으로 뜨게 하려면 Docker 데몬 자체가 활성화돼 있어야 한다.
sudo systemctl enable --now docker