モチベーション
DockerコンテナにSSH接続した際、基本的にカラー設定は無効化されている。無色だと作業効率が落ちるのでカラー化したいが毎度プロンプトや ls
や grep
などの各種色設定をログインする度に設定するのは骨が折れる。共有のプロジェクトなどは勝手に Dockerfile
にカラー設定を書き込むことが出来ない場合も多い。
そこで docker exec
でSSH接続する度に色設定情報を送り込むようにすればどのコンテナに接続しても好きな色設定 (+その他設定) でコンテナ内作業ができるので 捗ること請け合いだ!
方針
- カラー設定が書かれた
.bashrc
をホスト側に用意する - ホストの
.bashrc
をコンテナ内にコピーする - コンテナに環境変数
TERM=xterm-256color
を設定する - 上記をワンコマンドで実行するシェル関数を定義する
プロンプトのカラー設定
bash なら $PS1
zsh なら $PROMPT
にそれぞれプロンプトに表示する情報と色の設定を書き込む。
# 例
case "$TERM" in
xterm-color|*-256color) color_prompt=yes;;
esac
if [ "$color_prompt" = yes ]; then
# 色設定あり
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
# 端末の256色設定が無効なら色コードは入れない
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi
unset
参考:
ls
grep
のカラー設定
以下を .basrhc
に追記しておきます。
if [ -x /usr/bin/dircolors ]; then
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
alias ls='ls --color=auto'
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'
fi
ホストの .bashrc
をコンテナ内にコピーする
docker cp
コマンドを使ってホスト内のファイルをコンテナにコピーすることができる。
Docker では基本的に root ユーザーでのログインになるので root ユーザーのホームディレクトリである /root/
以下に .bashrc
をコピーする。
[書式] docker cp
ホストのファイルパス
コンテナ名:コンテナ内のパス
# 例:
# my_service イメージから my_service という名のコンテナを立ち上げる
docker run --rm -d -p 3000:3000 --name my_service my_service
# ホストの .basrc を コンテナの /root/ にコピーする
docker cp ~/.bashrc my_service:/root/
参考:
コンテナに TERM=xterm-256color
を設定する
環境変数 $TERM
に xterm-256color
が設定されているとターミナル内で扱える色が256色になります。
これをコンテナ内にログインするときに潜り込ませます。
docker exec -it my_service env TERM=xterm-256color /bin/bash
docker引数の --env
ではなくシェルの env
で設定しています。
コマンド一発でカラーシェルにログインする!
上記設定を一つの関数にまとめ一発で実行できるようにします。
~/.bashrc
に以下関数を書き込む。
(【追記】→ ~/bin/
のパスを通して ~/bin/docker-ssh
というシェルスクリプトを作ったほうが良さそう(※コメント参照) )
docker-ssh() {
cmd1="docker cp ~/.bashrc $1:/root/"
echo $cmd1 && eval $cmd1 && echo 'Copied! .bashrc'
cmd2="docker exec -it $@ env TERM=xterm-256color /bin/bash"
echo -e "\n" $cmd2 && eval $cmd2
}
使い方は、立ち上げたコンテナ名が my_service
の時に以下を実行するだけです。
$ docker-ssh my_service
docker cp ~/.bashrc web:/root/
Copied! .bashrc
docker exec -it web env TERM=xterm-256color /bin/bash
docker compose の場合
docker compose
で起動しているコンテナにSSH接続する際も基本的に同じ。間に compose
という文言が入るだけ。
# .bashrc に以下追記
docker-compose-ssh() {
cmd1="docker compose cp ~/.bashrc $1:/root/"
echo $cmd1 && eval $cmd1 && echo 'Copied! .bashrc'
cmd2="docker compose exec -it $@ env TERM=xterm-256color /bin/bash"
echo -e "\n" $cmd2 && eval $cmd2
}
# composeでコンテナ起動
docker compose up -d
# コンテナの起動状況を確認
$ docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
myapp-db-1 myapp-db "docker-entrypoint.s…" db 5 months ago Up 5 hours 0.0.0.0:15432->5432/tcp
myapp-web-1 myapp-web "/app/docker/web/ent…" web 4 days ago Up 5 hours 0.0.0.0:13000->3000/tcp
#=> 「web」 がサービス名
# webコンテナにログイン
docker-compose-ssh web
(余談)引数を変数にする
コマンドラインのオプション引数でよく使うものはグローバル変数化しておいたほうが何かと使い勝手いいかなと思って最初は以下のようにしていた。
docker-ssh() {
export DOCKER_EXEC_OPTIONS='-it --env TERM=xterm-256color'
docker cp ~/.bashrc $1:/root/
docker exec $DOCKER_EXEC_OPTIONS $@ /bin/bash
}
しかし、これだと以下のようなエラーになりダメだった。
$ docker-ssh web
unknown shorthand flag: ' ' in - --env TERM=xterm-256color
シェルが文字列を解釈する順序(?)的な問題かなと思って色々試すのが面倒になったので eval
にしたらうまく行った。
docker-ssh() {
export DOCKER_EXEC_OPTIONS='-it --env TERM=xterm-256color'
docker cp ~/.bashrc $1:/root/
eval "docker exec $DOCKER_EXEC_OPTIONS $@ /bin/bash" # eval で文字列をコマンドとして解釈
}
eval
はよくわかってないですがあまりよろしくないようなので、使わずにやりたいところ・・・。
わかる方教えてくださいませ!
↓
【追記】コメントにて詳しく教えて下さいました!