Dockerコンテナ内からGitリモートレポジトリへのpush方法

# Dockerコンテナ内からGitリモートレポジトリ(Githubなど)へのpush方法

## 1. 前提条件

- 開発環境であること。
- ローカル環境にDockerがインストールされている。
- ローカル環境にGitがインストールされている。
- ローカル環境におけるユーザの公開鍵をGithubに登録している。
- VSCodeに拡張機能であるDevcontainerがインストールされている。

## 2. 背景

- Dockerコンテナ内からGithubへpushしたい。
- 具体的には、VSCodeを用いたDockerコンテナ内での開発ツール、Devcontainerを使用する際にGithubに修正内容をコンテナ内からcommit、pushしたい。
- 現状では、Devcontainerとは別のターミナルを開いてローカル環境からcommit、pushしている。VScodeとターミナルの2窓状態となり、作業効率が落ちる。

## 3. 結論

- `Dockerfile`にてgitをインストールする

```Dockerfile:Dockerfile
# ベースイメージは適宜変更してください
FROM python:3.12.5-bullseye

WORKDIR /app

# gitのインストール
RUN apt-get update && \
  apt-get install -y --no-install-recommends \
  git \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/*

RUN git config --global --add safe.directory /app
```

- `docker-compose.yml`ファイルにて、ローカルユーザのssh秘密鍵(Githubに登録している公開鍵に対応したもの)をバインドマウント

```yml:docker-compose.yml
version: '3'
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    volumes: 
      - .:/app
      - ~/.ssh/id_rsa:/root/.ssh/id_rsa # ローカルユーザのssh秘密鍵をバインドマウント
    command: bash -c "tail -f /dev/null"
```

- `.devcontainer/devcontainer.json`にて上記のdocker-composeファイルを指定。

```json:.devcontainer/devcontainer.json
{
    "dockerComposeFile": "../docker-compose.yml",
    "service": "app",
    "workspaceFolder": "/app",
}
```

## 4. 詳細

### 最終的なファイル構成

Dockerコンテナ内からGitリモートレポジトリへのpushするためのローカル環境における最小構成です。カレントディレクトリ名は`git-in-docker`としています。

```bash
git-in-docker
├── .devcontainer
│   └── devcontainer.json
├── Dockerfile
└── docker-compose.yml
```
### Dockerfileについての説明

```Dockerfile:Dockerfile
FROM python:3.12.5-bullseye

WORKDIR /app

# gitのインストール
RUN apt-get update && \
  apt-get install -y --no-install-recommends \
  git \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/*

RUN git config --global --add safe.directory /app
```

以下の行でベースイメージを指定しています。使用したいイメージに適宜変更してください。今回は、Pythonのイメージを使用しています。

```Dockerfile
FROM python:3.12.5-bullseye
```

以下の行でローカルのカレントディレクトリをマウントするためのディレクトリを作成しています。今回は、`/app`ディレクトリにマウントすることを想定しています。

```Dockerfile
WORKDIR /app
```

以下の行でgitをインストールしています。

```Dockerfile
RUN apt-get update && \
  apt-get install -y --no-install-recommends \
  git \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/*
```

以下にgitをインストールした際の各コマンドについて記載します。

1. **`apt-get update`**:
   - DebianやUbuntuなどのDebian系Linuxディストリビューションで使用されるパッケージマネージャー`apt`のパッケージリストを更新します。これにより、最新のパッケージ情報を取得し、インストールやアップグレードを行う際に最新のバージョンが利用可能になります。

2. **`apt-get install -y --no-install-recommends git`**:
   - `git` パッケージをインストールします。`-y`オプションはプロンプトでの質問に自動的に「yes」と答えることを意味し、ユーザーの介入なしにインストールを進めることができます。
   - `--no-install-recommends` オプションを使用すると、パッケージのインストール時に推奨されるが必須ではない追加のパッケージをインストールしないようにします。これにより、必要最低限のパッケージのみがインストールされ、Dockerイメージのサイズを小さく保つことができます。

3. **`apt-get clean`**:
   - `apt-get` のキャッシュをクリアし、使用されなくなったパッケージファイルを削除します。これもイメージサイズを削減するための一般的な手法です。

4. **`rm -rf /var/lib/apt/lists/*`**:
   - `apt-get update` で生成されたパッケージリストのファイルを削除します。これはDockerイメージのサイズを最小化するためによく行われる作業で、ビルドプロセスが完了した後にこれらの一時ファイルを削除することで、不要なディスクスペースを削減します。

以下の行で`/app`ディレクトリを「安全なディレクトリ」としてGitのグローバル設定に追加しています。
これにより、コンテナ内でGit操作が行われる際に、`/app`ディレクトリがGitにとって安全であると認識されるようになります。

```Dockerfile
RUN git config --global --add safe.directory /app
```

### docker-compose.ymlについての説明

```yml:docker-compose.yml
version: '3'
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    volumes: 
      - .:/app
      - ~/.ssh/id_rsa:/root/.ssh/id_rsa # ローカルユーザのssh秘密鍵をバインドマウント
    command: bash -c "tail -f /dev/null"
```

以下の行で、`Dockerfile`にて定義したDockerコンテナ内の`/app`ディレクトリにローカルのカレントディレクトリをマウントしています。

```yml
volumes: 
  - .:/app
```

以下の行で、ローカルユーザのssh秘密鍵(Githubに登録している公開鍵に対応する秘密鍵)をDockerコンテナ内の`/root/.ssh/id_rsa`にマウントしています。

```yml
- ~/.ssh/id_rsa:/root/.ssh/id_rsa
```

### .devcontainer/devcontainer.jsonについての説明

```json:.devcontainer/devcontainer.json
{
    "dockerComposeFile": "../docker-compose.yml",
    "service": "app",
    "workspaceFolder": "/app",
}
```

以下の行で、`docker-compose.yml`ファイルを指定しています。

```json
"dockerComposeFile": "../docker-compose.yml",
```

## 5. 動作検証 

実際にコンテナを起動し、コンテナ内からGithubへpushできるか検証します。  
以下に検証手順を示します。

1 . ローカル環境にて以下のコマンドでDockerイメージをビルドします。

```bash
$ pwd
/path/to/git-in-docker
$ docker compose build --no-cache
```

2 . ローカル環境にて以下のコマンドでDockerコンテナを起動します。

```bash
$ docker compose up -d
```

3 . devcontainerを使用してDockerコンテナに接続します。

左下「><」ボタン→「コンテナーで再度開く」ボタンをクリックします。
しばらくすると、Dockerコンテナ内のターミナルが開いて、左下が「><開発コンテナー」となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3487776/e61e0772-0f94-2cd7-2985-71613f6421d0.png)

※devcontainerを使用していない方は、以下のコマンドでコンテナに接続可能です。

```bash
$ docker compose exec app bash
```

4 . コンテナ内から以下のコマンドで検証用のファイルを作成します。

```bash
$ echo "Hello git-in-docker" > test.txt
```

5 . `git status`、`git add test.txt`、`git commit -m "Add test.txt"`、`git push`の順にコマンドを実行して、正常に動作すればOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3487776/1a907c37-f582-ae51-02c3-62a818f027f6.png)

## 6. 終わりに

以上で、Dockerコンテナ内からGitリモートレポジトリ(Githubなど)へのpush方法について解説しました。
Dockerコンテナ内での開発ツール、Devcontainerを使用する際にGithubに修正内容をコンテナ内からcommit、pushする際に参考にしていただければ幸いです。
誤りやアドバイス等ございましたら、お気軽にコメントいただければと思います。