Web Terminal w/docker

[TOC]

개요

회사에서 방화벽 때문에 집 서버(?) 또는 AWS 서버 접근을 위해 아이폰, 아이패드를 쓰면서 구글 클라우드 웹베이스 (http 80) 터미널 서비스 사용할 수 있으면 좋겠다 생각에 찾아보다 포기했는데 오늘(`18. 10/05)  혹시나 하고 검색할 하니 딱 그래서 기존 NextCloud 컨테이너 HTTPS 서비스를 엮어서 만들어 보기로 함

참고 :

Setup Web Terminal using Wetty Docker Image – Chairat.me – Medium,

krishnasrinivas/wetty - Docker Hub

GitHub - krishnasrinivas/wetty: Terminal in browser over http/https. (Ajaxterm/Anyterm alternative, but much better)

What is Wetty? Web + tty

Wetty = Web + tty.
Terminal over HTTP and HTTPS. Wetty uses ChromeOS’ terminal emulator (hterm) which is a full fledged implementation of terminal emulation written entirely in Javascript. Also it uses websockets instead of Ajax and hence better response time.
Source: https://github.com/krishnasrinivas/wetty

git clone

  1. 복제 (Clone) Wetty repository on GitHub.
bori@BorilikeGame:/media/usbhdd1$ git clone git@github.com:krishnasrinivas/wetty.git
'wetty'에 복제합니다...
The authenticity of host 'github.com (192.30.255.113)' can't be established.
RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'github.com,192.30.255.113' (RSA) to the list of known hosts.
git@github.com: Permission denied (publickey).
fatal: 리모트 저장소에서 읽을 수 없습니다

올바른 접근 권한이 있는지, 그리고 저장소가 있는지
확인하십시오.
bori@BorilikeGame:/media/usbhdd1$ git clone https://github.com/krishnasrinivas/wetty.git
'wetty'에 복제합니다...
remote: Enumerating objects: 214, done.
remote: Total 214 (delta 0), reused 0 (delta 0), pack-reused 214
오브젝트를 받는 중: 100% (214/214), 381.18 KiB | 587.00 KiB/s, 완료.
델타를 알아내는 중: 100% (102/102), 완료.

Dockerfile 설정 및 이미지 생성

  • 원본  Dockerfile
FROM node:0.10.38
MAINTAINER Nathan LeClaire <nathan@docker.com>
ADD . /app
WORKDIR /app
RUN npm install
RUN apt-get update
RUN apt-get install -y vim
RUN useradd -d /home/term -m -s /bin/bash term
RUN echo 'term:term' | chpasswd
EXPOSE 3000
ENTRYPOINT ["node"]
CMD ["app.js", "-p", "3000"]

This tells us that:
  • Wetty is a Node.js application.
  • It creates a new user term which we can use to logon.
  • The web interface is exposed at port 3000

host User vs Docker container User

user  term > bori (term은 docker 컨테이너 user, bori는 host user)

plex의 경우 환경 변수로 UID/GID을 전달 하여 권한을 동일하게 생성, host에서 볼경우 host UID와 동일한 User 명으로 보임

Dockerfile :

version: '2'
services:
  plex:
    container_name: plex
    image: plexinc/pms-docker:public
    restart: unless-stopped
    environment:
      - TZ=Asia/Seoul
      - PLEX_CLAIM=claim-RzsUttmeYHj5T9EBk44F
      - PLEX_UID=123 # host user deluge's UID
      - PLEX_GID=33  # host group www-data UID
    network_mode: host
    volumes:
      - /var/lib/deluge/config:/config
      - /var/lib/deluge/transcode:/transcode
      - /media/usbhdd1/shares:/data
      - /media/usbhdd2:/media/data2

실행 프로세스 :

bori@BorilikeGame:/media/usbhdd1/plex/pms-docker$ ps -ef|grep plex
root      7188  5731  0 20:08 ?        00:00:00 s6-supervise plex
deluge    7190  7188  0 20:08 ?        00:00:00 /bin/sh -c LD_LIBRARY_PATH=/usr/lib/plexmediaserver /usr/lib/plexmediaserver/Plex\ Media\ Server
deluge    7199  7190  0 20:08 ?        00:00:24 /usr/lib/plexmediaserver/Plex Media Server
deluge    7301  7199  0 20:08 ?        00:00:28 Plex Plug-in [com.plexapp.system] /usr/lib/plexmediaserver/Resources/Plug-ins-10d48da0d/Framework.bundle/Contents/Resources/Versions/2/Python/bootstrap.py --server-version 1.13.8.5395-10d48da0d /usr/lib/plexmediaserver/Resources/Plug-ins-10d48da0d/System.bundle
deluge    7410  7199  0 20:08 ?        00:00:52 /usr/lib/plexmediaserver/Plex DLNA Server
deluge    7413  7199  0 20:08 ?        00:00:00 /usr/lib/plexmediaserver/Plex Tuner Service /usr/lib/plexmediaserver/Resources/Tuner/Private /usr/lib/plexmediaserver/Resources/Tuner/Shared 1.13.8.5395-10d48da0d 32600 /waitmutex

동일하게 안해주면 term 어떤 user의 권한을 갖게 될까? term vs root ? Root 정답

bori@BorilikeGame:/media/usbhdd1/wetty$ ps -ef |grep node
root       854     1  0 10월05 ?      00:00:12 /sbin/mount.ntfs-3g /dev/sdb1 /media/usbhdd1 -o rw,noexec,nosuid,nodev,permissions,users
root     25295 25276  0 01:03 ?        00:00:00 node app.js -p 300

원본 Dockerfile로 local 이미지 생성

  • node.js (0.10.38) docker 이미지  pull
  • 이미지 관리자 등록
  • Host ./app 디렉토리는 docker 이미지에 추가
  • docker 실행 디렉토리를 /app로 설정
  • npm 설치 및 wetty 설치 (pty.js@0.3.1 install /app/node_modules/pty.js)
  • RUN apt-get update
  • RUN apt-get install -y vim
  • RUN useradd -d /home/term -m -s /bin/bash term
  • RUN echo 'term:term' | chpasswd
  • EXPOSE 3000
  • ENTRYPOINT ["node"]
  • CMD ["app.js", "-p", "3000"]
bori@BorilikeGame:/media/usbhdd1/wetty$ docker build -t test1/wetty .
Sending build context to Docker daemon   1.04MB
Step 1/12 : FROM node:0.10.38
0.10.38: Pulling from library/node
df22f9f3e4ec: Pull complete
a3ed95caeb02: Pull complete
cd3f33f3eac9: Pull complete
29b84dd39cd5: Pull complete
a85bd624bab4: Pull complete
505aadf959ef: Pull complete
8eedbbe23e7b: Pull complete
Digest: sha256:e2a5045398e7f867e51c73eee2b3e6ec64716d1907c4c37acb5dee0493154d95
Status: Downloaded newer image for node:0.10.38
 ---> 82073591bd0c
Step 2/12 : MAINTAINER Nathan LeClaire <nathan@docker.com>
 ---> Running in 14c453cdcae0
Removing intermediate container 14c453cdcae0
 ---> 172721b4b00e
Step 3/12 : ADD . /app
 ---> a71bb11bc69b
Step 4/12 : WORKDIR /app
 ---> Running in 520a73b4fcf5
Removing intermediate container 520a73b4fcf5
 ---> ebd355bb28bd
Step 5/12 : RUN npm install
 ---> Running in 9f7b6e51b0e8
npm WARN deprecated minimatch@0.2.14: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated coffee-script@1.3.3: CoffeeScript on NPM has moved to "coffeescript" (no hyphen)
npm WARN deprecated connect@2.14.1: connect 2.x series is deprecated
npm WARN deprecated graceful-fs@1.2.3: please upgrade to graceful-fs 4 for compatibility with current and future versions of Node.js

> pty.js@0.3.1 install /app/node_modules/pty.js
> node-gyp rebuild

make: Entering directory '/app/node_modules/pty.js/build'
  CXX(target) Release/obj.target/pty/src/unix/pty.o
  SOLINK_MODULE(target) Release/obj.target/pty.node
  COPY Release/pty.node
make: Leaving directory '/app/node_modules/pty.js/build'
npm WARN deprecated minimatch@0.3.0: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated static-favicon@1.0.0: use serve-favicon module
grunt-mkdir@0.1.3 node_modules/grunt-mkdir

grunt-contrib-clean@0.6.0 node_modules/grunt-contrib-clean
└── rimraf@2.2.8

optimist@0.6.1 node_modules/optimist
├── wordwrap@0.0.3
└── minimist@0.0.10

grunt-shell@1.3.1 node_modules/grunt-shell
├── object-assign@4.1.1
├── npm-run-path@1.0.0 (path-key@1.0.0)
└── chalk@1.1.3 (escape-string-regexp@1.0.5, supports-color@2.0.0, ansi-styles@2.2.1, has-ansi@2.0.0, strip-ansi@3.0.1)

load-grunt-tasks@3.5.2 node_modules/load-grunt-tasks
├── arrify@1.0.1
├── resolve-pkg@0.1.0 (resolve-from@2.0.0)
├── pkg-up@1.0.0 (find-up@1.1.2)
└── multimatch@2.1.0 (array-differ@1.0.0, array-union@1.0.2, minimatch@3.0.4)

grunt-git@0.3.7 node_modules/grunt-git
└── flopmang@0.0.1 (underscore.string@2.4.0, underscore@1.9.1)

grunt@0.4.5 node_modules/grunt
├── dateformat@1.0.2-1.2.3
├── which@1.0.9
├── getobject@0.1.0
├── eventemitter2@0.4.14
├── rimraf@2.2.8
├── colors@0.6.2
├── async@0.1.22
├── grunt-legacy-util@0.2.0
├── hooker@0.2.3
├── exit@0.1.2
├── nopt@1.0.10 (abbrev@1.1.1)
├── glob@3.1.21 (inherits@1.0.2, graceful-fs@1.2.3)
├── lodash@0.9.2
├── minimatch@0.2.14 (sigmund@1.0.1, lru-cache@2.7.3)
├── coffee-script@1.3.3
├── underscore.string@2.2.1
├── iconv-lite@0.2.11
├── findup-sync@0.1.3 (glob@3.2.11, lodash@2.4.2)
├── grunt-legacy-log@0.1.3 (grunt-legacy-log-utils@0.1.1, underscore.string@2.3.3, lodash@2.4.2)
└── js-yaml@2.0.5 (argparse@0.1.16, esprima@1.0.4)

socket.io@1.7.4 node_modules/socket.io
├── object-assign@4.1.0
├── socket.io-adapter@0.5.0
├── has-binary@0.1.7 (isarray@0.0.1)
├── debug@2.3.3 (ms@0.7.2)
├── socket.io-parser@2.3.1 (isarray@0.0.1, component-emitter@1.1.2, json3@3.3.2, debug@2.2.0)
├── engine.io@1.8.5 (base64id@1.0.0, cookie@0.3.1, engine.io-parser@1.3.2, ws@1.1.5, accepts@1.3.3)
└── socket.io-client@1.7.4 (to-array@0.1.4, indexof@0.0.1, component-emitter@1.2.1, object-component@0.0.3, component-bind@1.0.0, backo2@1.0.2, parseuri@0.0.5, engine.io-client@1.8.5)

express@3.5.1 node_modules/express
├── methods@0.1.0
├── merge-descriptors@0.0.2
├── debug@0.8.1
├── cookie-signature@1.0.3
├── range-parser@1.0.0
├── fresh@0.2.2
├── buffer-crc32@0.2.1
├── cookie@0.1.1
├── mkdirp@0.3.5
├── commander@1.3.2 (keypress@0.1.0)
├── send@0.2.0 (mime@1.2.11)
└── connect@2.14.1 (response-time@1.0.0, pause@0.0.1, method-override@1.0.0, vhost@1.0.0, connect-timeout@1.0.0, static-favicon@1.0.0, qs@0.6.6, serve-static@1.0.2, basic-auth-connect@1.0.0, morgan@1.0.0, bytes@0.2.1, raw-body@1.1.3, errorhandler@1.0.0, csurf@1.0.0, cookie-parser@1.0.1, compression@1.0.0, express-session@1.0.2, serve-index@1.0.1, multiparty@2.2.0)

pty.js@0.3.1 node_modules/pty.js
├── extend@1.2.1
└── nan@2.3.5
Removing intermediate container 9f7b6e51b0e8
 ---> 58bae3cbe0cb
Step 6/12 : RUN apt-get update
 ---> Running in 0ddf84411480
Get:1 http://security.debian.org jessie/updates InRelease [44.9 kB]
Get:2 http://security.debian.org jessie/updates/main amd64 Packages [676 kB]
Ign http://httpredir.debian.org jessie InRelease
Get:3 http://httpredir.debian.org jessie-updates InRelease [145 kB]
Get:4 http://httpredir.debian.org jessie Release.gpg [2420 B]
Get:5 http://httpredir.debian.org jessie Release [148 kB]
Get:6 http://httpredir.debian.org jessie-updates/main amd64 Packages [23.0 kB]
Get:7 http://httpredir.debian.org jessie/main amd64 Packages [9098 kB]
Fetched 10.1 MB in 14s (697 kB/s)
Reading package lists...
Removing intermediate container 0ddf84411480
 ---> 1911c80f38fb
Step 7/12 : RUN apt-get install -y vim
 ---> Running in e39beccd561e
Reading package lists...
Building dependency tree...
Reading state information...
The following extra packages will be installed:
  libgpm2 vim-common vim-runtime
Suggested packages:
  gpm ctags vim-doc vim-scripts
The following NEW packages will be installed:
  libgpm2 vim vim-common vim-runtime
0 upgraded, 4 newly installed, 0 to remove and 207 not upgraded.
Need to get 6219 kB of archives.
After this operation, 28.9 MB of additional disk space will be used.
Get:1 http://httpredir.debian.org/debian/ jessie/main libgpm2 amd64 1.20.4-6.1+b2 [34.0 kB]
Get:2 http://httpredir.debian.org/debian/ jessie/main vim-common amd64 2:7.4.488-7+deb8u3 [185 kB]
Get:3 http://httpredir.debian.org/debian/ jessie/main vim-runtime all 2:7.4.488-7+deb8u3 [5048 kB]
Get:4 http://httpredir.debian.org/debian/ jessie/main vim amd64 2:7.4.488-7+deb8u3 [953 kB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 6219 kB in 8s (715 kB/s)
Selecting previously unselected package libgpm2:amd64.
(Reading database ... 27882 files and directories currently installed.)
Preparing to unpack .../libgpm2_1.20.4-6.1+b2_amd64.deb ...
Unpacking libgpm2:amd64 (1.20.4-6.1+b2) ...
Selecting previously unselected package vim-common.
Preparing to unpack .../vim-common_2%3a7.4.488-7+deb8u3_amd64.deb ...
Unpacking vim-common (2:7.4.488-7+deb8u3) ...
Selecting previously unselected package vim-runtime.
Preparing to unpack .../vim-runtime_2%3a7.4.488-7+deb8u3_all.deb ...
Adding 'diversion of /usr/share/vim/vim74/doc/help.txt to /usr/share/vim/vim74/doc/help.txt.vim-tiny by vim-runtime'
Adding 'diversion of /usr/share/vim/vim74/doc/tags to /usr/share/vim/vim74/doc/tags.vim-tiny by vim-runtime'
Unpacking vim-runtime (2:7.4.488-7+deb8u3) ...
Selecting previously unselected package vim.
Preparing to unpack .../vim_2%3a7.4.488-7+deb8u3_amd64.deb ...
Unpacking vim (2:7.4.488-7+deb8u3) ...
Processing triggers for mime-support (3.58) ...
Processing triggers for hicolor-icon-theme (0.13-1) ...
Setting up libgpm2:amd64 (1.20.4-6.1+b2) ...
Setting up vim-common (2:7.4.488-7+deb8u3) ...
Setting up vim-runtime (2:7.4.488-7+deb8u3) ...
Processing /usr/share/vim/addons/doc
Setting up vim (2:7.4.488-7+deb8u3) ...
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/vim (vim) in auto mode
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/vimdiff (vimdiff) in auto mode
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/rvim (rvim) in auto mode
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/rview (rview) in auto mode
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/vi (vi) in auto mode
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/view (view) in auto mode
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/ex (ex) in auto mode
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/editor (editor) in auto mode
Processing triggers for libc-bin (2.19-18) ...
Removing intermediate container e39beccd561e
 ---> c60d37c468ed
Step 8/12 : RUN useradd -d /home/term -m -s /bin/bash term
 ---> Running in f82a2f83d110
Removing intermediate container f82a2f83d110
 ---> c56b63b3269b
Step 9/12 : RUN echo 'term:term' | chpasswd
 ---> Running in 15a67f045d1c
Removing intermediate container 15a67f045d1c
 ---> 0cdc1b15fa91
Step 10/12 : EXPOSE 3000
 ---> Running in 0346033eb953
Removing intermediate container 0346033eb953
 ---> 5e8ec625fb12
Step 11/12 : ENTRYPOINT ["node"]
 ---> Running in 5b0afc0f4aee
Removing intermediate container 5b0afc0f4aee
 ---> 8c971e854126
Step 12/12 : CMD ["app.js", "-p", "3000"]
 ---> Running in b78782e4c09b
Removing intermediate container b78782e4c09b
 ---> bd1510e14524
Successfully built bd1510e14524
Successfully tagged test1/wetty:latest
bori@BorilikeGame:/media/usbhdd1/wetty$ docker image ls -a
REPOSITORY                               TAG                 IMAGE ID            CREATED              SIZE
test1/wetty                              latest              bd1510e14524        About a minute ago   786MB

컨테이너 생성

docker-compose.yml 파일 생성

  • 기존 nginx-proxy 및 SSL 컨테이너 활용 - 환경 변수 및 docker bridge NW  apache_porxy-tier 연결
  • 공식 도메인으로 wty.igotoo.pw 사용
version: '3'
services:
 webtty:
  container_name:  webtty
  image: test1/wetty
  restart: always
  environment:
   - VIRTUAL_HOST=wty.igotoo.pw
   - LETSENCRYPT_HOST=wty.igotoo.pw
   - LETSENCRYPT_EMAIL=igotoo@gmail.com

networks:
  default:
   external:
     name: apache_proxy-tier

문제 및 해결

문제 :  문법 오류 , 원인 및 해결 : docker-compose 파일 생성시 tab 아닌 space로 간격 조정 ---> yml 파일 작성 문번 공부 필요

문제 : 기존 nextcloud 컨테이너의 내부 네트워크 proxy-tier에 연결 안됨, 원인 및 해결 : porxy-tier는 wetty 컨테이너에게는 외부 네트워크이므로 externl 로 연결 해주어야 함. docker-compose는 하나 이상의 컨테이너를 묶어 별도의 공간(?) 을 만드는 것 같은 --> 공부  (참고 : Networking in Compose | Docker Documentation)

docker NW

bori@BorilikeGame:~$ docker network ls
NETWORK ID          NAME                   DRIVER              SCOPE
d323e7509923        apache_default         bridge              local
347d9a3ffcfb        apache_proxy-tier      bridge              local
9d76205ec57f        bridge                 bridge              local
3b89db5f0168        composetest_default    bridge              local
204769fe9090        docker-gen_default     bridge              local
a0615c56eae4        docker-proxy_default   bridge              local
ad7188507811        host                   host                local
c9b78c272179        none                   null                local

wty.igotoo.pw DNS 등록

구글 도메인에서 DNS에 wty.igotoo.pw 등록

CNAME으로 추가

항상 헤갈리는 CNAME 이란?

출처 : 인터넷의 주소록 DNS 서비스 ─ 기반기술에 대해서... | the Great World Meson

img
img
인터넷 주소의 해석; 구매하는 도메인은 domain name. top-level domain 이 조합된 주소를 구매한다.
  • 하나의 domain name(ex : igotoo.pw) 으로 여러가지 서비스(ex : plexmediaserver, nextcloud, webtty 등) 를 제공할 경우 subdomain으로 분리 이때 subdomain 명을 CNAME 이라고 함
  • A record(Public IP 매핑와 domain name)와 1:1 매핑 되며 IP로 매핑 하면 안됨
A Canonical Name record (abbreviated as CNAME record) is a type of resource record in the Domain Name System (DNS) which maps one domain name to another, referred to as the Canonical Name.
This can prove convenient when running multiple services (like an FTP server and a webserver; each running on different ports) from a single IP address. One can, for example, point ftp.example.comand www.example.com to the DNS entry for example.com, which in turn has an A record which points to the IP address. Then, if the IP address ever changes, one only has to record the change in one place within the network: in the DNS A record for example.com.
CNAME records must always point to another domain name, never directly to an IP address.
출처 : CNAME record - Wikipedia

컨테이너 실행

docker-compose up -d
  • chrome 브라우저로 접속 결과
  • Host 접근하기를 원했는데 webtty를 설치하면서 생성된 컨테이너에 접근하는 게 됬었음. 이거슨 Docker의 개념을 모르는 무식한 짓이었음 Doker 컨테이너는 Host와 분리된 독립된 환경인데  이 컨테이너에 접속해서 호스트를 제어하겠다고 했으니 ....
  • 기존 proxy-ssl 도커 서비스를 이용해서 아니 좀더 심플하게 도커 컨테이너 nginx 컨네이너 proxy를 활용 할 수 있는 방법이 없을까? nginx 설정에 호스트 웹서버를 reverse proxy 할 수 있도록 해주면 될 거 같음
  • 컨테이너에서 host를 ssh로 연결이 더 쉬운 방법 참고한 사이트에서도 이방법을 사용했는데 건성으로 보아서 미처 모르고 있었음

Docker 이미지 및 컨테이너 재 생성

Dockerfile 수정

User 변경 : term --> igotoo

기본 linux 명령어 실행을 위해 busybox 설치

Host ssh 접속을 위한 Host의 bori user id_rsa 복사/권한(600) 설정

FROM node:0.10.38
MAINTAINER igotoo@gmail.com
ADD . /app
WORKDIR /app
RUN npm install
RUN apt-get update
RUN apt-get install -y vim
RUN apt-get install -y busybox
RUN useradd -d /home/igotoo -m -s /bin/bash igotoo
RUN echo 'igotoo:xxxx' | chpasswd
RUN mkdir /home/igotoo/.ssh
COPY id_rsa /home/igotoo/.ssh/id_rsa
RUN chmod 600 /home/igotoo/.ssh/id_rsa && chown -Rf igotoo /home/igotoo/.ssh
EXPOSE 3000
ENTRYPOINT ["node"]
CMD ["app.js", "-p", "3000"]

이미지 생성

docker build -t test2/wetyy .

문제 및 해결

문제 : COPY 오류

원인 : Host 경로(/home/bori/.ssh/id_rsa)로 설정 해주어서 파일 not found 에러 발생

The <src> path must be inside the context of the build; you cannot COPY ../something /something, because the first step of a docker build is to send the context directory (and subdirectories) to the docker daemon.

해결 : id_rsa를 docker pjt context 내부 즉 docker-compose 실행 디렉토리(/media/usbhdd1/wetty)에 복사 후 경로 설정 없이 id_rsa 컨테이너로 복사

문제 : ssh 접속 불가

  • 원인 : host user bori private key를 컨테이너에 복사 해주었으나 정작 호스트 접속시 public key 등록 안된것으로 판단 오류 발생
  • 해결 :  host authorized_key에 bori's public key 복사.
  • ssh 오류 발생 매번 헤갈림 접속 클라이언트 비밀키(id_rsa)를 가지고 있어야 하며 서버는 클라이언트 공개키(id_rsa.pub)를 서버 authorized_keys 에 저장하고 있어야 하며 권한은 600 이어야 함

chrome 브라우저 접속결과 : 성공 !!!