Skip to content

Commit 6b09bb4

Browse files
committed
Refactor devenv docker administration
1 parent a07c362 commit 6b09bb4

21 files changed

Lines changed: 1315 additions & 319 deletions

‎.dockerignore‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.git
2+
.github
3+
.DS_Store
4+
*.log
5+
tmp
6+
pdf_output
7+
pdf_output_test

‎.github/workflows/deploy_image.yaml‎

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,13 @@ on:
44

55
jobs:
66
build-and-push-image:
7-
runs-on: ubuntu-20.04
7+
runs-on: ubuntu-22.04
8+
permissions:
9+
contents: read
10+
packages: write
811
steps:
912
- name: Checkout
10-
uses: actions/checkout@v2
11-
12-
- name: Extract metadata (tags, labels) for Docker
13-
id: meta
14-
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
15-
with:
16-
images: |
17-
zarathucorp/devenv-docker
13+
uses: actions/checkout@v4
1814

1915
- name: Set TAG env
2016
run: echo "RELEASE_VERSION=v$(date +'%Y%m%d')" >> $GITHUB_ENV
@@ -23,29 +19,29 @@ jobs:
2319
run: echo "container tag will be 'latest' and '${{ env.RELEASE_VERSION }}'"
2420

2521
- name: Set up Docker Buildx
26-
uses: docker/setup-buildx-action@v1
22+
uses: docker/setup-buildx-action@v3
2723

2824
- name: Login to DockerHub/
29-
uses: docker/login-action@v1
25+
uses: docker/login-action@v3
3026
with:
3127
username: ${{ secrets.DOCKERHUB_USERNAME }}
3228
password: ${{ secrets.DOCKERHUB_TOKEN }}
3329

3430
- name: Login to GitHub Container Registry
35-
uses: docker/login-action@v2
31+
uses: docker/login-action@v3
3632
with:
3733
registry: ghcr.io
3834
username: ${{ github.actor }}
3935
password: ${{ secrets.GHCR_TOKEN }}
4036

4137
- name: Build and push
4238
id: docker_build
43-
uses: docker/build-push-action@v4
39+
uses: docker/build-push-action@v6
4440
with:
45-
file: dockerfile
41+
file: Dockerfile
4642
push: true
4743
tags: |
48-
dao0312/zarathu-dev:latest
44+
dao0312/zarathu_dev:latest
4945
dao0312/zarathu_dev:${{ env.RELEASE_VERSION }}
5046
ghcr.io/${{ github.repository_owner }}/devenv:latest
5147
ghcr.io/${{ github.repository_owner }}/devenv:${{ env.RELEASE_VERSION }}

‎Dockerfile‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
FROM rocker/shiny:4.5.1
2+
3+
ENV DEBIAN_FRONTEND=noninteractive
4+
5+
RUN apt-get update && apt-get install -y --no-install-recommends \
6+
apt-transport-https \
7+
build-essential \
8+
ca-certificates \
9+
curl \
10+
dirmngr \
11+
gdebi-core \
12+
git \
13+
gnupg \
14+
libcairo2-dev \
15+
libcurl4-gnutls-dev \
16+
libpam-google-authenticator \
17+
libssl-dev \
18+
libxt-dev \
19+
libxml2-dev \
20+
locales \
21+
openssh-server \
22+
pandoc \
23+
software-properties-common \
24+
sudo \
25+
supervisor \
26+
vim \
27+
wget \
28+
&& rm -rf /var/lib/apt/lists/*
29+
30+
RUN locale-gen en_US.UTF-8
31+
ENV LANG=en_US.UTF-8 \
32+
LC_ALL=en_US.UTF-8
33+
34+
COPY zarathu/dependencies /tmp/zarathu-dependencies
35+
36+
RUN Rscript "/tmp/zarathu-dependencies/CRAN.R" \
37+
&& Rscript "/tmp/zarathu-dependencies/REMOTE.R" \
38+
&& R -e "shinytest::installDependencies()" \
39+
&& rm -rf /tmp/zarathu-dependencies
40+
41+
RUN /rocker_scripts/install_rstudio.sh
42+
43+
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
44+
COPY bin/devenv-admin /usr/local/bin/devenv-admin
45+
COPY lib/devenv-admin /usr/local/lib/devenv-admin
46+
COPY shiny-server.conf /etc/shiny-server/shiny-server.conf
47+
COPY supervisord.conf /etc/supervisord.conf
48+
49+
RUN chmod +x \
50+
/usr/local/bin/entrypoint.sh \
51+
/usr/local/bin/devenv-admin \
52+
&& mkdir -p /etc/ssh/sshd_config.d /run/sshd
53+
54+
EXPOSE 3838 8787 22
55+
56+
HEALTHCHECK --interval=30s --timeout=5s --start-period=90s --retries=3 \
57+
CMD /usr/local/bin/devenv-admin healthcheck
58+
59+
ENTRYPOINT ["/bin/bash", "/usr/local/bin/entrypoint.sh"]

‎README.md‎

Lines changed: 150 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,174 @@
1-
# How to run?
1+
# Zarathu Devenv Docker
22

3-
## Get Image
3+
R/Shiny, RStudio Server, SSH를 함께 제공하는 회사 개발용 컨테이너입니다.
44

5-
You can select pre-built image or build yourself.
5+
기본 이미지에는 회사 사용자 계정이나 고정 비밀번호를 만들지 않습니다. 계정은 컨테이너 시작 시 env로 부트스트랩하거나, 실행 후 `devenv-admin`으로 생성합니다.
66

7-
### Use pre-build image
7+
## Build
88

9-
See [Docker Hub](https://hub.docker.com/r/dao0312/zarathu_dev)
9+
```bash
10+
docker build -t devenv-docker:latest .
11+
```
1012

11-
### Build
13+
CI는 `Dockerfile`을 사용해 Docker Hub와 GitHub Container Registry에 이미지를 배포합니다.
1214

13-
or you can build yourself.
15+
## Persistent home volume
1416

15-
At first, clone this repository by
17+
`/home`은 반드시 이미지/컨테이너 내부가 아니라 별도 Docker volume에 마운트해서 사용합니다. 이렇게 해야 이미지를 업데이트하거나 컨테이너를 새로 만들어도 사용자 파일, Shiny 앱, RStudio 설정, SSH key, OTP secret이 유지됩니다.
1618

17-
`git clone https://github.com/zarathucorp/devenv-docker`
19+
```bash
20+
docker volume create zarathu-home
21+
```
1822

19-
Move to folder
23+
실행할 때는 항상 아래처럼 `/home`에 연결합니다.
2024

21-
`cd devenv-docker`
25+
```bash
26+
-v zarathu-home:/home
27+
```
2228

23-
Run
29+
Linux 계정 자체와 그룹 membership은 `/home`에 저장되지 않습니다. 컨테이너를 새로 만든 뒤에는 `devenv-admin`으로 같은 계정을 다시 생성해야 합니다.
2430

25-
`docker build -t devenv-docker:v241207 .`
31+
## Run without a bootstrap user
2632

27-
Tag is optional.
33+
```bash
34+
docker run -itd \
35+
--name zarathu-devenv \
36+
-p 3838:3838 \
37+
-p 8787:8787 \
38+
-p 22:22 \
39+
-v zarathu-home:/home \
40+
devenv-docker:latest
41+
```
2842

29-
## Run Image
43+
이 방식으로 시작하면 사용자 계정이 없습니다. 컨테이너에 root로 들어가서 계정을 만듭니다.
3044

31-
It uses two ports, 3838 and 8787.
45+
```bash
46+
docker exec -it zarathu-devenv bash
47+
devenv-admin user add alice --password 'change-me' --sudo no
48+
```
3249

33-
Run
50+
Shiny 앱은 `http://<host>:3838/alice/<app-name>/` 형태로 접근합니다. RStudio는 `http://<host>:8787`에서 Linux 계정으로 로그인합니다.
3451

35-
`docker run -itd -p 3838:3838 -p 8787:8787 -v <host volume location>:/home devenv-docker:v241207`
52+
## Run with a bootstrap user
3653

37-
You can access localhost:3838/shiny/<user_name> for Shiny Server and localhost:8787 for RStudio Server
54+
비밀번호를 파일로 넘기는 방식을 권장합니다.
3855

39-
#### Why volume share is important?
56+
```bash
57+
printf '%s' 'change-me' > /srv/zarathu-bootstrap-password
4058

41-
Without volume share, container usage will get more and more bigger.
59+
docker run -itd \
60+
--name zarathu-devenv \
61+
-p 3838:3838 \
62+
-p 8787:8787 \
63+
-p 22:22 \
64+
-v zarathu-home:/home \
65+
-v /srv/zarathu-bootstrap-password:/run/secrets/bootstrap-password:ro \
66+
-e DEVENV_BOOTSTRAP_USER=alice \
67+
-e DEVENV_BOOTSTRAP_PASSWORD_FILE=/run/secrets/bootstrap-password \
68+
-e DEVENV_BOOTSTRAP_SUDO=no \
69+
devenv-docker:latest
70+
```
4271

43-
To save storage, use -v option.
72+
이미 존재하는 사용자는 기본적으로 비밀번호를 덮어쓰지 않습니다. 덮어써야 하면 `DEVENV_BOOTSTRAP_FORCE_PASSWORD=true`를 추가합니다.
4473

45-
## **Please leave message to issue tab for any inquiries**
74+
## Account management
4675

47-
I'll be happy to help you.
76+
컨테이너 안에서 `devenv-admin`을 사용합니다.
4877

49-
For example, I'm using nginx for https support. If you want to know how, leave it at issue tab!
78+
```bash
79+
devenv-admin user add alice --password 'change-me' --sudo no
80+
devenv-admin user passwd alice
81+
devenv-admin user sudo alice on
82+
devenv-admin user key add alice --ssh-key 'ssh-ed25519 AAAA... alice@example'
83+
devenv-admin user key list alice
84+
devenv-admin user delete alice --remove-home
85+
```
86+
87+
`devenv-admin`은 컨테이너 안에서 `/usr/local/bin/devenv-admin`으로 실행되고, 내부 구현은 `/usr/local/lib/devenv-admin` 아래 기능별 모듈로 분리됩니다.
88+
89+
## SSH policy
90+
91+
SSH는 VPN 또는 내부망에서만 노출하는 전제입니다. 기본값은 비밀번호 인증 비활성화입니다.
92+
93+
컨테이너 시작 시 설정:
94+
95+
```bash
96+
-e DEVENV_SSH_PASSWORD_AUTH=false
97+
```
98+
99+
실행 중 변경:
100+
101+
```bash
102+
devenv-admin ssh password-auth status
103+
devenv-admin ssh password-auth on
104+
devenv-admin ssh password-auth off
105+
```
106+
107+
SSH 키는 `devenv-admin user key add`로 사용자별 `authorized_keys`에 추가합니다.
108+
109+
## RStudio OTP
110+
111+
RStudio TOTP 로그인을 옵션으로 사용할 수 있습니다. 기본값은 비활성화입니다.
112+
113+
컨테이너 시작 시 OTP PAM 모듈 활성화:
114+
115+
```bash
116+
-e DEVENV_RSERVER_OTP=true
117+
```
118+
119+
실행 중 활성화 및 사용자 초기화:
120+
121+
```bash
122+
devenv-admin otp enable
123+
devenv-admin otp init alice
124+
devenv-admin otp status
125+
devenv-admin otp disable
126+
```
127+
128+
OTP를 켜면 `otp_exempt` 시스템 그룹이 생성됩니다. 일반 사용자는 RStudio 비밀번호 입력창에 비밀번호가 아니라 OTP만 입력합니다. OTP를 면제하고 비밀번호 로그인을 허용할 사용자는 아래 명령으로 관리합니다.
129+
130+
```bash
131+
devenv-admin otp exempt add alice
132+
devenv-admin otp exempt list
133+
devenv-admin otp exempt remove alice
134+
```
135+
136+
`otp_exempt` 사용자는 OTP가 활성화되어 있어도 OTP 없이 기존 비밀번호만으로 로그인할 수 있습니다. OTP가 켜져 있고 `otp_exempt`가 아닌 사용자는 `devenv-admin otp init <user>`로 OTP secret을 먼저 만들어야 로그인할 수 있습니다.
137+
138+
사용자가 터미널에서 직접 `google-authenticator`를 실행해 자기 홈 디렉터리에 OTP secret을 만들어도 됩니다. `devenv-admin otp init <user>`는 root가 같은 초기화 명령을 해당 사용자로 대신 실행해 주는 관리용 편의 명령입니다.
139+
140+
## Operations
141+
142+
상태 점검:
143+
144+
```bash
145+
devenv-admin status
146+
devenv-admin doctor
147+
devenv-admin healthcheck
148+
```
149+
150+
RStudio 세션 초기화:
151+
152+
```bash
153+
devenv-admin rstudio reset alice
154+
```
155+
156+
Shiny 앱 디렉터리 초기화:
157+
158+
```bash
159+
devenv-admin shiny init alice
160+
```
161+
162+
## External access
163+
164+
RStudio와 Shiny를 외부망에 열 경우 컨테이너를 직접 TLS 종단점으로 쓰지 말고, 호스트나 인프라 계층의 reverse proxy를 앞에 둡니다. RStudio는 WebSocket을 사용하므로 proxy에서 WebSocket upgrade와 충분한 timeout을 허용해야 합니다.
165+
166+
권장 노출 모델:
167+
168+
- SSH: VPN 또는 내부망 전용
169+
- RStudio: reverse proxy + TLS + 접근 제어
170+
- Shiny: reverse proxy + TLS + 필요한 앱별 접근 제어
171+
172+
## Package installation
173+
174+
CRAN 패키지는 `zarathu/dependencies/CRAN.R`, GitHub 패키지는 `zarathu/dependencies/REMOTE.R`에서 관리합니다.

0 commit comments

Comments
 (0)