dotfiles(neovim,vim,tmux) + Docker でどこでも環境構築

# dotfiles + Dockerの利点

私は、普段neovimとwslを使って開発をしています。
しかし、学校・職場で同じ環境を再現するのは不可能なことが多いです。また、できたとしても(dotfilesの)OSごとの設定は面倒です。

そこで、dotfilesとDockerfileを使い、環境ごとgitで管理します。
githubに上げれば、いつでもどこでも自分の好きな環境が```docker compose up -d```で立ち上がります。面倒な依存関係も、OSごとの対応もいりません。

# 構成

TL;DR すぐに環境を立ち上げたい人へ
1. dotfiles + Dockerの作り方
2. 詰まったところとその対応

# 環境
- win11 * wsl2
- ubuntu22.04(docker)
- nvim

# TL;DR 

早くイメージを使いたい人へ

### 1. 以下を```git clone```

Dockerfiles

https://github.com/WATA-Haru/Dockerfiles

### 2. sample-docker-compose.ymlを自分の環境に合わせて編集

- 直接、編集したいディレクトリをdocker-composeのvolumeでマウント
- ホストマシンと同じsshのkeyを使用することでDocker内のterminalから、githubへのpushが可能に


```yml: docker-compose.yml
version: '3'
services:
  dotfiles:
    image: hwata001/dotfiles:latest
    volumes:
      - type: bind
        source: "<you-working-dir>"
        target: "/home"
      - type: bind
        source: "<your-ssh-key>" #your github ssh key dir
        target: "/root/.ssh"
```

###  3. コンテナの立ち上げ
これで立ち上がって入れるはず
```shell
docker compose up -d
docker compose run -it dotfiles /bin/bash
```

### 4. コンテナの削除
終わったら削除も忘れずに
```shell
docker ps -a
docker stop <containerID>
docker rm <containerID>
```

## dotfiles Dockerfiles Docker-image
**dotfiles**

https://github.com/WATA-Haru/dotfiles/tree/main

**Dockerfiles**

https://github.com/WATA-Haru/Dockerfiles


**dotfiles Docker image**

https://hub.docker.com/repository/docker/hwata001/dotfiles/general

# Docker + dotfiles の作り方

1. dotfilesをgithubで管理
2. Dockerfileを作成
3. Docker imageをDocker hubにpushする
4. docker-compose.ymlの作成・volumeの指定

## 1. dotfilesをgithubで管理
githubで管理します。リポジトリはpublicにしましょう。

https://github.com/WATA-Haru/dotfiles/tree/main

## 2. Dockerfileを作成

```Dockerfile:Dockerfile
FROM ubuntu:22.04

SHELL ["/bin/bash", "-c"]

RUN apt update && \
    apt-get update && \
    apt install -y curl git ripgrep tar unzip vim wget python3 python3-pip python3-venv tmux

# nvim install
RUN wget https://github.com/neovim/neovim/releases/download/stable/nvim-linux64.tar.gz && \
    tar -zxvf nvim-linux64.tar.gz && \
    mv nvim-linux64/bin/nvim usr/bin/nvim && \
    mv nvim-linux64/lib/nvim usr/lib/nvim && \
    mv nvim-linux64/share/nvim/ usr/share/nvim && \
    rm -rf nvim-linux64 && \
    rm nvim-linux64.tar.gz

RUN apt install -y locales && \
    locale-gen ja_JP.UTF-8

# add my dotfiles
RUN git clone -b main https://github.com/WATA-Haru/dotfiles.git

# you can mount your github ssh-key by using docker compose volume
RUN mkdir ~/.ssh

# bash symbolic link
RUN rm -f ~/.bashrc && \
    ln -s /dotfiles/.bash_aliases ~/.bash_aliases && \
    ln -s /dotfiles/.bashrc ~/.bashrc

# nvim symbolic link
RUN rm -rf ~/.config/nvim && \
    mkdir ~/.config/ && \
    ln -s /dotfiles/nvim ~/.config/nvim

# vim symbolic link
RUN rm -f ~/.vimrc && \
    rm -rf ~/.vim && \
    ln -s /dotfiles/vim/vimrc ~/.vimrc && \
    ln -s /dotfiles/vim/vim ~/.vim

# tmux plugin manager install
RUN git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm

# tmux symbolic link
RUN rm -f ~/.tmux.conf && \
    ln -s /dotfiles/tmux/tmux.conf ~/.tmux.conf
	
# install npm for lsp
RUN apt-get install -y ca-certificates gnupg && \
    curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \
    NODE_MAJOR=20 && \
    echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \ 
    apt-get update && \
    apt-get install nodejs -y

# dev tools for 42school
# norminette
RUN python3 -m pip install --upgrade pip setuptools
RUN python3 -m pip install norminette

RUN . ~/.bashrc
RUN nvim +:q
```

### Dockerfilesについて
重要なのはこのコードです。先ほどのdotfilesをcloneしています。

```Dockerfile
# add my dotfiles
RUN git clone -b main https://github.com/WATA-Haru/dotfiles.git
```

Dockerfileを作ったらbuildします。
```shell
docker build -t dotfiles .
```

### (注意) build後にdotfilesを変更した場合
Dockerfileを作っている途中で変更点に気付き、dotfilesを編集したとします。
この場合、--no-cacheをつけて再びbuildしましょう。
```shell
docker build --no-cache -t dotfiles .
```

Dockerは、Dockerfileに変更がなければ、CACHEされた内容を使いまわします。dotfilesが変更されていたとしてもDockerfile内のリポジトリのURLに変更がないのでDocker側は検知できません。そのため、dotfilesの最新の内容を読み込みたい場合は```--no-cache```を指定するというわけです。


※後半にnorminetteという、[筆者の入っている学校](https://42tokyo.jp/)で使うための設定が入っています。ほとんどの人は必要ありません。自作する方は不要なので消してください。


## 3. Docker imageをDocker hubにpushする

[Docker Hub](https://hub.docker.com/)に登録しておいてください。
リポジトリは自身の```<My-Docker-ID>/<My-Repository-Name>```になります。自分の好きな名前のリポジトリ名を作成してください。このリポジトリ名はあとで使用します。


**1. イメージ名変更**
先ほど作ったイメージ(dotfiles)の名前を、登録したリポジトリ名に変更します。

```shell
docker tag dotfiles <My-Docker-ID>/<My-Repository-Name>
```

これで、```docker image ls```すると、dotfilesと同じIDを持った```<My-Docker-ID>/<My-Repository-Name>```が確認できます。

**2. Docker hubにpush**
```
docker push <My-Docker-ID>/<My-Repository-Name>
```


## 4. docker-compose.ymlの作成・volumeの指定



```yml: docker-compose.yml
version: '3'
services:
  dotfiles:
    image: hwata001/dotfiles:latest
    volumes:
      - type: bind
        source: "<you-working-dir>"
        target: "/home"
      - type: bind
        source: "<your-ssh-key>" #your github ssh key dir
        target: "/root/.ssh"
```

```<you-working-dir>```に自身のマウントしたい作業ディレクトリ
```<your-ssh-key>```に自身のgithubのsshキーが入っているディレクトリ
を指定してマウントします。


こちら非常に参考になりました。

https://zenn.dev/sarisia/articles/0c1db052d09921


そして、 

```shell
docker compose up -d
docker compose run -it dotfiles /bin/bash
```

これでDocker内のターミナルにアクセスできます。
tmuxも使えます!

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261812/a7e8e961-6d86-ff52-0644-959501a1d280.png)


# 詰まったところとその対応

### tmuxでなぜか日本語入力ができない -> ```tmux -u```

```tmux -u```をエイリアスに指定しました。utf-8が使えるようになるオプションです。

### tmuxのpluginを入れたのに背景色が変わらない!(凡ミス) -> PowerShellの設定だった
- terminal(筆者の環境ではPowershell)本体の色設定が必要でした。
- Powershellの上部を右クリック->settings->Appearance->背景色変更

### tmuxに入ったが、ユーザ名が白いままだ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261812/d0f91c94-d5fb-19c6-5840-f0d71e5f977c.png)

こんな感じです。wslと同じようにこうしたかったので、wslの```.bashrc```を流用しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261812/8ed9f061-1eaf-ddd1-21bf-e8a38e50b1dd.png)

こちらをご覧ください。
https://github.com/WATA-Haru/dotfiles/blob/main/.bashrc


### Neovim, vimのカラースキームの色が変わらない

以下を追加しました。
```shell:tmux.conf

set-option -g default-terminal "screen-256color"
set-option -ga terminal-overrides "$TERM:Tc"
set -sa terminal-overrides "*:Tc"
```

```vim:.vimrc
if $TMUX != ""
   let &t_8f = "\<Esc>[38:2:%lu:%lu:%lum"
   let &t_8b = "\<Esc>[48:2:%lu:%lu:%lum"
endif
```
```init.lua```の設定はいらない。

参考

https://www.reddit.com/r/vim/comments/exvvil/colorscheme_problems_in_vim_only_inside_tmux/

### NeovimとTmuxのClipboardをホストマシン(windows * wsl)と共有する
※Macでは動作未検証です。

こちらを参考にそのまま書きました。

https://qiita.com/hellomyzn/items/8f1fbfe1316decf36a9e

**neovim**
```init.lua
vim.opt.clipboard = "unnamedplus"

if vim.env.TMUX then
    vim.g.clipboard = {
        name = 'tmux',
        copy = {
            ["+"] = {'tmux', 'load-buffer', '-w', '-'},
            ["*"] = {'tmux', 'load-buffer', '-w', '-'},
        },
        paste = {
            ["+"] = {'tmux', 'save-buffer', '-'},
            ["*"] = {'tmux', 'save-buffer', '-'},
        },
        cache_enabled = false,
    }
end
```

**tmux**
```shell: tmux.conf
# tmux clipboard
bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "pbcopy"
bind -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "pbcopy"
```

### vimでホストマシンのクリップボードからペースト(ctrl + v)した際にインデントが崩れる

こちらを参考にそのまま書きました。

https://qiita.com/ryoff/items/ad34584e41425362453e

```vim:.vimrc
if &term =~ "xterm"
    let &t_ti .= "\e[?2004h"
    let &t_te .= "\e[?2004l"
    let &pastetoggle = "\e[201~"

    function XTermPasteBegin(ret)
        set paste
        return a:ret
    endfunction

    noremap <special> <expr> <Esc>[200~ XTermPasteBegin("0i")
    inoremap <special> <expr> <Esc>[200~ XTermPasteBegin("")
    cnoremap <special> <Esc>[200~ <nop>
    cnoremap <special> <Esc>[201~ <nop>
endif

```

### docker内で、gitのsafe.directoryが指定できない

以下だとなぜかできないときがありました。

```shell
 git config --global --add safe.directory <dir>
```

以下の書き方ならできました。謎です。
```shell
git config --system --add safe.directory "${PWD}"
```

https://qiita.com/P-man_Brown/items/5628ef68f51d1acf38e0



# 解決していない問題

1. vimからホストOSへのクリップボード共有(Neovimからはできる)

    vimはホストOSとのクリップボード共有ができませんでした。vim-gtk3をインストールしたり、stack overflowを見たりしても無理でした。何かいい方法があれば教えてください。

2. コンテナに入るタイミングで毎回githubのユーザ情報を打つ必要がある

```shell
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
```

これを毎回聞かれるので自動化しようとしましたが、Dockerfilesに書く以外の方法が見つからなかったので諦めました。Dockerfileはpublicなので、私の固有の情報は入れたくありませんでした。


# 参考にした記事

こちらの記事が非常に参考になりました。ありがとうございました。

https://zenn.dev/tamago3keran/articles/30b581bde514e6

https://zenn.dev/sarisia/articles/0c1db052d09921


# (再掲) dotfiles Dockerfiles Docker-image 一覧
**dotfiles**

https://github.com/WATA-Haru/dotfiles/tree/main

**Dockerfiles**

https://github.com/WATA-Haru/Dockerfiles


**dotfiles Docker image**

https://hub.docker.com/repository/docker/hwata001/dotfiles/general

Docker初心者なので不十分な点があればご指摘ください。