俺が使う俺のためのオレオレdocker イメージを作った
- マイナーで容量もでかいarchlinuxベース
- 日本語環境適用
- 自分のdotfiles適用
- (ここから2020.4.30 update)
- dockerでvolumeをマウントしたときのファイルのowner問題で一通り悩んだ挙句、dotfilesとかhomeをchownする時間が惜しくて、どうせ自分しか使わないだろうし、結局はUID=1000, GID=1000, USERNAME=u1and0でbuildし直しました。
- u1and0/neovim, u1and0/zplugの継承関係を入れ替えました。
- Python環境をpyenv使わずに再構築しました。
- docker-in-docker環境を新規作成しました。
- docker-compose.ymlを追記しました。
- (ここから2021.1.5 update)
- archlinux official image の 毎日アップデートされている方のbase-devel有り版を選択しました。
- Rust環境を新規作成しました。
ベースイメージと自分の作ったカスタムイメージの継承関係
$ docker inspect --format="{{.Size}}" \
u1and0/{archlinux,neovim,zplug,vim-go,python-conda,rust,docker}:latest |
numfmt --to=iec
777M
1.2G
1.3G
2.4G
4.4G
3.3G
1.6G
archlinux/archlinux base-devel-20220101.0.42885 716MB
└── u1and0/archlinux v5.1.0 777MB
└── u1and0/neovim v5.1.1 1.2GB
└── u1and0/zplug v5.1.1 1.3GB
└── u1and0/vim-go v3.0.0 2.4GB
└── u1and0/python-conda v1.0.0 4.4GB
└── u1and0/rust v1.0.0 3.3GB
└── u1and0/docker v1.0.0 1.6GB
u1and0/archlinux
archlinux/baseをベースにしました。- 公式のarchlinux/archlinuxをベースにしました。
- u1and0/dotfiles を適用しています。
- pacmanによる公式パッケージだけでなく、yayによるAURパッケージのインストールも可能です。
- パッケージダウンロード元サーバーをreflectorで選択したファイルを
/etc/pacman.d/mirrorlist
に適用しています。(更新日2019.02.01) -
ロケール日本語 > helpとかが日本語表示(しかしmanのインストールでエラー。manを日本語どころか英語でも見れない。解決策模索中)(2020.4.30 update) - manが見れない問題はpacman.confのNoExtractを消せば見ることが出来ました。Archlinux docker image man pages? (2021.1.5 update)
- yayをマルチステージビルド化 (2021.1.5 update)
# Usage:
# $ docker run -it --rm -v `pwd`:/work -w /work u1and0/archlinux
#
# For building:
# $ git clone https://github.com/u1and0/docker_archlinux_env
# $ docker build --build-arg USERNAME=${USERNAME} --build-arg branch="develop" -t u1and0/archlinux .
# Archlinux official image daily build version
FROM archlinux/archlinux:base-devel
# Get reflector Server setting for faster download
# Same as `reflector --verbose --country Japan -l 10 --sort rate`
COPY pacman.conf /etc/pacman.conf
COPY mirrorlist /etc/pacman.d/mirrorlist
# Japanese setting
ARG SETLANG="ja_JP"
ENV LANG="${SETLANG}.UTF8"\
LC_NUMERIC="${SETLANG}.UTF8"\
LC_TIME="${SETLANG}.UTF8"\
LC_MONETARY="${SETLANG}.UTF8"\
LC_PAPER="${SETLANG}.UTF8"\
LC_MEASUREMENT="${SETLANG}.UTF8"
# Locale setting
ARG GLIBVER="2.33"
ARG LOCALETIME="Asia/Tokyo"
RUN : "Copy missing language pack '${SETLANG}'" &&\
curl http://ftp.gnu.org/gnu/libc/glibc-${GLIBVER}.tar.bz2 | tar -xjC /tmp &&\
cp /tmp/glibc-${GLIBVER}/localedata/locales/${SETLANG} /usr/share/i18n/locales/ &&\
rm -rf /tmp/* &&\
: "Overwrite locale-gen" &&\
echo ${SETLANG}.UTF-8 UTF-8 > /etc/locale.gen &&\
locale-gen &&\
: "Set time locale, Do not use 'timedatectl set-timezone Asia/Tokyo'" &&\
ln -fs /usr/share/zoneinfo/${LOCALETIME} /etc/localtime
# Package update
# `pacman-key --init` must run at first
RUN pacman-key --init &&\
pacman-key --populate archlinux &&\
pacman -Syu --noconfirm git openssh &&\
: "Clear cache" &&\
pacman -Qtdq | xargs -r pacman --noconfirm -Rcns
ARG USERNAME=u1and0
# docker build --build-arg USERNAME=${USERNAME} -t u1and0/archlinux .
ARG UID=1000
ARG GID=1000
RUN echo "Build start with USERNAME: $USERNAME UID: $UID GID: $GID" &&\
pacman -Sy &&\
: "Add user ${USERNAME} for yay install" &&\
groupadd -g ${GID} ${USERNAME} &&\
useradd -u ${UID} -g ${GID} -m -s /bin/bash ${USERNAME} &&\
passwd -d ${USERNAME} &&\
mkdir -p /etc/sudoers.d &&\
touch /etc/sudoers.d/${USERNAME} &&\
echo "${USERNAME} ALL=(ALL) ALL" > /etc/sudoers.d/${USERNAME} &&\
mkdir -p /home/${USERNAME}/.gnupg &&\
echo 'standard-resolver' > /home/${USERNAME}/.gnupg/dirmngr.conf &&\
chown -R ${USERNAME}:${USERNAME} /home/${USERNAME} &&\
mkdir /build &&\
chown -R ${USERNAME}:${USERNAME} /build
# yay install
COPY --from=u1and0/yay:latest /usr/bin/yay /usr/bin/yay
# My dotfiles
WORKDIR /home/${USERNAME}
USER ${USERNAME}
# `--build-arg=branch=v1.15.1` のようにしてブランチ名、タグ名指定しなければ
# デフォルトではdevelopブランチをcloneしてくる
ARG branch="develop"
RUN git clone --branch $branch\
https://github.com/u1and0/dotfiles.git dotfiles &&\
: "Replace dotfiles" &&\
mv -f dotfiles/.git . &&\
git reset --hard &&\
rm -rf dotfiles
CMD ["/bin/bash"]
LABEL maintainer="u1and0 <e01.ando60@gmail.com>"\
description="archlinux image. AUR packages are able to install by yay. yay -S {package}"\
description.ja="Archlinux イメージ。yayによるAURパッケージインストール可能. yay -S {package}, dotfiles develop branch"\
version="arlhlinux:5.1.0"
u1and0/neovim
- u1and0/archlinuxをベースにしました。
- この記事はこのdockerイメージを使って書きました。
- C-Jから始まるキーバインドでdenite, 例えばC-JC-Nで現在ディレクトリ下のファイル検索、C-JC-Fで現在ファイルを検索
- F5でファイラーNERDTreeをサイドバーで開く
- などなど
# Neovim container
# *Using my dotfiles
# *Get plugins by dein
# * Inherit from u1and0/archlinux <- archlinux/base
#
# Usage:
# $ docker pull u1and0/neovim
# $ docker run -it --rm -v `pwd`:/work -w /work u1and0/neovim nvim [filenames] ...
FROM u1and0/archlinux:latest
# Neovim install
# USER u1and0 or somebody except root
RUN yay -Syyu --noconfirm neovim\
python-neovim\
fd\
fzf\
ripgrep\
w3m\
pygmentize\
ctags\
global \
man \
man-pages-ja &&\
: "Remove all packages cache " &&\
yay -Scc --noconfirm
# Plugins insall
# Install & Update plguins & vimproc
RUN nvim +UpdateRemotePlugins +VimProcInstall +q
LABEL maintainer="u1and0 <e01.ando60@gmail.com>"\
description="OS=archlinux, editor=neovim, dotfiles=u1and0/dotfiles, plugin manager=dein"\
version="neovim:v5.1.1"
u1and0/zplug
- u1and0/neovimをベースにしました。
- docker hubのビルドテストは何故か失敗していますが、ローカル環境でのビルドは成功しています。リモートのビルドが失敗する原因を調査中。
- 別環境のWindows上のVirtualBox内のArchlinuxで
docker run u1and0/zplug
で動作確認しました。
# zsh/zplug container
# * zshell powered by zplug
# * Using my dotfiles
# * Inherit from u1and0/neovim <- u1and0/archlinux <- archlinux/base
#
# Usage:
# $ docker pull u1and0/zplug
# $ docker run -it --rm -v `pwd`:/work -w /work u1and0/zplug
FROM u1and0/neovim:latest
# Reinstall packages required by zplug
RUN sudo pacman -Syyu --noconfirm zsh awk git tig &&\
: "Remove cache" &&\
pacman -Qtdq | xargs -r sudo pacman --noconfirm -Rcns
# Install zplug plugins
RUN git clone --depth 1 https://github.com/zplug/zplug .zplug &&\
zsh -ic "source .zshrc &&\
source .zplug/init.zsh &&\
source .zplug.zsh &&\
zplug install"
ENV SHELL="/usr/bin/zsh"
CMD ["/usr/bin/zsh"]
LABEL maintainer="u1and0 <e01.ando60@gmail.com>"\
description="OS=archlinux editor=neovim shell=zsh_with_zplug"\
version="zplug v5.1.1"
u1and0/vim-go
- u1and0/neovimをベースにしました。
-
fatih/vim-go,
zchee/deopleteプラグインインストール済み(2020.4.30 update) -
:GoInstallBinaries
で手に入るツール取得済み
# Usage:
# docker run -it --rm -v `pwd`:/work -w /work u1and0/golang
FROM u1and0/zplug:latest
# Install go
RUN sudo pacman -Syu --noconfirm go &&\
pacman -Qtdq | xargs -r sudo pacman --noconfirm -Rcns
# pacman -Scc の代わり
# gopath setting
# go install より前に指定する
ARG LOUSER=u1and0
ENV GO111MODULE="on"\
GOPATH="/home/${LOUSER}/go"\
PATH="$GOPATH/bin:$PATH"
# May be included vim-go GoUpdateBinaries command
# Install go tools
# RUN go install \
# golang.org/x/tools/gopls@latest \
# golang.org/x/tools/cmd/goimports@latest \
# golang.org/x/tools/cmd/guru@latest \
# golang.org/x/tools/cmd/gorename@latest &&\
# go clean -cache
# RUN go get -u \
# github.com/golangci/golangci-lint/cmd/golangci-lint \
# golang.org/x/lint/golint \
# github.com/rogpeppe/godef \
# github.com/kisielk/errcheck \
# github.com/jstemmer/gotags \
# github.com/klauspost/asmfmt/cmd/asmfmt \
# github.com/fatih/motion \
# github.com/zmb3/gogetdoc \
# github.com/josharian/impl \
# Install vim-go & LSP server
RUN nvim +GoUpdateBinaries +LspInstallServer +q && go clean -cache
# Install REPL
RUN go install github.com/x-motemen/gore/cmd/gore@latest &&\
go install github.com/stamblerre/gocode@latest &&\
go get github.com/k0kubun/pp@latest &&\
go clean -cache
LABEL maintainer="u1and0 <e01.ando60@gmail.com>"\
description="golang env with neovim"\
description.ja="golang開発環境with neovim"\
version="vim-go:v3.0.0"
u1and0/docker_python-conda
noimage
# Python dev docker image
#
# Usage:
# In host machine's shell
# $ docker pull u1and0/python-conda
# $ docker run -it --rm -v `pwd`:/work -w /work u1and0/python-conda
#
# Using other command with activating `conda`
# $ docker run -it --rm -v `pwd`:/work -w /work\
# u1and0/python-conda bash -c ". .bashrc && python"
# $ docker run -it --rm -v `pwd`:/work -w /work\
# u1and0/python-conda bash -c ". .bashrc && ipython"
# $ docker run -it --rm -v `pwd`:/work -w /work\
# u1and0/python-conda bash -c ". .bashrc && nvim"
# $ docker run -P -it --rm -v `pwd`:/work -w /work\
# u1and0/python-conda bash -c ". .bashrc && jupyter notebook"
#
# In contaner
# Just type
# $ ipython
# or
# $ jupyter notebook
# or
# $ nvim
FROM u1and0/zplug:latest
# !!
# USER=u1and0 not root user
# !!
# Install miniconda3-latest & restore conda packages
RUN yay -Syyu --noconfirm miniconda3 &&\
yay -Scc &&\
sudo ln -s /opt/miniconda3/etc/profile.d/conda.sh /etc/profile.d/conda.sh
RUN sudo pacman -Syyu --noconfirm python-pip otf-ipafont &&\
pacman -Qtdq | xargs -r sudo pacman --noconfirm -Rcns
ENV PATH /etc/profile.d/:$PATH
# Base packages
RUN source /etc/profile.d/conda.sh &&\
sudo conda install --quiet --yes \
numpy \
pandas \
scipy \
matplotlib \
seaborn \
more-itertools \
h5py \
line_profiler \
ipython \
jupyter \
notebook \
conda-forge::jupyterthemes \
conda-forge::jupyter_contrib_nbextensions \
conda-forge::neovim \
flake8 \
pyflakes \
pylint \
pygments \
yapf \
autopep8 \
conda-build &&\
sudo conda remove --quiet --yes --force qt pyqt && \
: "clean cache" &&\
conda build purge-all
# Dev packages
RUN source /etc/profile.d/conda.sh &&\
sudo conda install --quiet --yes \
scikit-learn \
plotly \
conda-forge::cufflinks-py \
dash \
dash-renderer \
dash-core-components \
dash-html-components \
dash-table &&\
sudo conda remove --quiet --yes --force qt pyqt && \
: "clean cache" &&\
conda build purge-all
# !!
# SHELL=/usr/bin/zsh at parent layer
# !!
EXPOSE 8888
LABEL maintainer="u1and0 <e01.ando60@gmail.com>"\
description="python dev container"\
description.ja="python開発用コンテナ。ipython, jupyter notebook, neovimによる開発"\
build_version="python:v1.0.0"
u1and0/rust
noimage
# Usage:
# docker run -it --rm -v `pwd`:/work -w /work u1and0/rust
FROM u1and0/zplug:latest
# Install Rust
RUN : "Setup Rust" &&\
curl -sSf https://sh.rustup.rs | sh -s -- -y
RUN source ${HOME}/.cargo/env &&\
: "Setup Rust nightly version" &&\
rustup toolchain install nightly-2021-06-07 &&\
rustup default nightly-2021-06-07
RUN source ${HOME}/.cargo/env &&\
: "Install racer-src" &&\
cargo install racer
RUN source ${HOME}/.cargo/env &&\
: "Install Rust Language Server" &&\
rustup component add rust-analysis \
rust-src
# rls install tips [Nightly Rustにおいて、RLSがrustupコマンドでインストールできない時に代わりに探してくれるツール(cargo-rls-install)を作った](https://qiita.com/s4i/items/0538f7fe4874980ccf27)
RUN source ${HOME}/.cargo/env &&\
: "Install rls Rust Language Server" &&\
cargo install cargo-rls-install \
cargo-edit &&\
cargo rls-install -y
#RUN :"Install rust-doc" &&\
# curl -fsSL https://static.rust-lang.org/dist/rust-1.0.0-i686-unknown-linux-gnu.tar.gz | tar -xz
LABEL maintainer="u1and0 <e01.ando60@gmail.com>"\
description="rust lang env with neovim"\
version="rust:v1.0.0"
u1and0/docker
noimage
# My shell env built on Archlinux.
# docker manager for docker.
# sync docker directory of host machine.
#
# * docker
# * tmux
# * neovim
# * zsh( zplug )
# * dotfiles(@u1and0)
#
# Usage:
# `docker run -it -v /var/run/docker.sock:/var/run/docker.sock u1and0/docker` -v `pwd`:/work
FROM u1and0/zplug:latest
# Install tmux && tmux-plugins
RUN git submodule update --init --recursive .tmux/plugins/tpm &&\
sudo pacman -Syyu --noconfirm tmux &&\
${HOME}/.tmux/plugins/tpm/scripts/install_plugins.sh &&\
pacman -Qtdq | xargs -r sudo pacman --noconfirm -Rcns
# Install docker
RUN sudo pacman -Syyu --noconfirm docker pigz &&\
pacman -Qtdq | xargs -r sudo pacman --noconfirm -Rcns
ENV SHELL "/usr/bin/zsh"
CMD ["/usr/bin/zsh"]
LABEL maintainer="u1and0 <e01.ando60@gmail.com>"\
description="Docker in Docker with archlinux image"\
version="v1.0.0"
詳しくはページ上のREADMEで。
docker compose
docker-compose up
するだけで環境が整う
# maintainer: u1and0 <e01.ando60@gmail.com>
# version 3.7 for docker version 18.06+
# see https://docs.docker.com/compose/compose-file/
# What for:
# docker in docker dev.env
#
# * master: zsh & zplug env. Parents for all docker image.
# * jupyter: python env. It can use ipython & jupyter
# * vim-go: golang env.
#
# Usage:
# $ cd /path/to/composeset
# $ docker-compose up
# $ docker exec -it composeset_master_1 zsh -l
#
# # Login master container then...
# $ tmux
#
# # Login go env
# $ docker exec -it composeset_vim-go_1 zsh -l
#
# # Login python env
# $ docker exec -it composeset_jupyter_1 bash -c ". .bashrc && zsh"
#
# # Login python env as ipython
# $ docker exec -it composeset_jupyter_1 bash -c ". .bashrc && ipython"
#
# # Setup git after login
# $ git stash
# $ git fetch
# $ git checkout origin/develop
# $ git switch -c develop
# $ git stash pop
# for shortly
# $ gst && g fetch && gch origin/develop && g switch -c develop && gst pop
#
# # Setup pacman after login
# $ pacman -Sy archlinux-keyring
# $ pacman -Syu
version: '3'
services:
master:
image: "u1and0/docker:latest"
tty: true
volumes:
- "${HOME}:/home/u1and0/home"
- "${HOME}/Dropbox:/home/u1and0/Dropbox"
- "${HOME}/.zsh_history:/home/u1and0/.zsh_history"
- "${HOME}/yankring_history_v2.txt:/home/u1and0/yankring_history_v2.txt"
- "/mnt/e/Users/U1and0:/mnt/e"
- "/var/run/docker.sock:/var/run/docker.sock"
restart: "always"
environment:
- "HOST=master"
ports:
- "8000:8000"
jupyter:
# jupyter tagはpasswordを設定したイメージ
# [Jupyter on Dockerでパスワードの設定方法が分からないあなたへ](https://qiita.com/Yusuke-Shimizu/items/731ca71b3c4c3649ec7f)
image: "u1and0/python-conda:latest"
volumes:
- "${HOME}:/home/u1and0/home"
- "${HOME}/Dropbox:/home/u1and0/Dropbox"
- "${HOME}/.zsh_history:/home/u1and0/.zsh_history"
- "${HOME}/yankring_history_v2.txt:/home/u1and0/yankring_history_v2.txt"
- "/mnt/e/Users/U1and0:/mnt/e"
environment:
- "PYTHONPATH=/home/u1and0/Dropbox/Program/python"
- "HOST=conda"
command: "bash -c '. .bashrc && jupyter notebook'"
ports:
- "8888:8888" # jupyter notebook
- "8880:8880" # plotly dash
vimgo:
image: "u1and0/vim-go:latest"
tty: true
volumes:
- "${HOME}:/home/u1and0/home"
- "${HOME}/Dropbox:/home/u1and0/Dropbox"
- "${HOME}/.zsh_history:/home/u1and0/.zsh_history"
- "${HOME}/yankring_history_v2.txt:/home/u1and0/yankring_history_v2.txt"
- "/mnt/e/Users/U1and0:/mnt/e"
environment:
- "HOST=vim-go"
# - "GOPATH=/home/u1and0/go"
working_dir: "$GOPATH"
ports:
- "8080:8080"
cap_add:
- "SYS_PTRACE" # for golang debugger
rust:
image: "u1and0/rust:latest"
tty: true
volumes:
- "${HOME}:/home/u1and0/home"
- "${HOME}/Dropbox:/home/u1and0/Dropbox"
- "${HOME}/.zsh_history:/home/u1and0/.zsh_history"
- "${HOME}/yankring_history_v2.txt:/home/u1and0/yankring_history_v2.txt"
- "/mnt/e/Users/U1and0:/mnt/e"
environment:
- "HOST=rust"
ports:
- "8089:8089"
なぜArchlinuxか
新しいバージョンのパッケージが手に入りやすいから
pacman -S [package name]
で最新版のパッケージをインストールします。
UbuntuやCentOSに落ちているパッケージは古い安定版が多いですが、Archlinux標準のパッケージマネージャpacman
を使えばより新しいバージョンを手に入れることができます。
Archlinuxはローリング・リリース
方式を取るLinuxディストロです。
pacmanデータベースが管理している最新のパッケージ同士の依存関係を解決することがOSアップデートの役割も担っています。
pacman使いたいから
上と同じ。MSYS2やCmderからUNIX入門したので、パッケージマネージャーはpacman1が一番慣れているし、pacmanが一番いいパッケージマネージャだとと思ってます。(デスクトップPCはUbuntuユーザー、仮想環境はArchlinuxユーザー。)
bacpacというpacmanのバックアップツールがあり、ワンコマンドで次の機能が使えます。
- pacmanで入れたパッケージのgistへのバックアップ
- ローカルへ復元
- バックアップしたパッケージのリスト表示
- バックアップと現在インストール状況の差分表示
forkして自分で使いやすく改造していますu1and0/bacpac。
bacpacの親リポジトリはメンテナンスを終了しています。
AURからもインストールできる
yay2をインストールしてあるdockerイメージをベースにしているのでyayがつかえます。
pacman -S
で見つからないパッケージはたいていyay -S
で手に入ります。
yayは AURからパッケージを落としてきます。
Ubuntuでいうapt-add-repository [reponame] && apt install [packagename]
をyay -S [packagename]
で済ませるということですね。
実験用
上述の通りArchlinuxベースのコンテナは最新版のパッケージを手に入れやすいので、パッケージの最新機能を試してはコンテナを壊して、再構築してまた試して、という使い方を想定しています。
dockerはきれいな本番環境を作っていく目的にもいいですが、こういう実験的環境構築にも向いていると思います。
Archlinuxは上述したようなアップデート方式から「永遠の不安定版」と呼ばれているので、実機環境よりは仮想環境向きでしょう。
Powerlineフォントについて
三角形のフォントを表示するにはホストマシンにPowerline fontのインストールと「ターミナルのフォント変更作業」が必要です。
インストール方法はgithubに書かれているので従ってください。
docker開発環境を作ってみたとき気づいたメリットとデメリット
メリット
-
エラーやワーニングがでないようにdotfilesを最適化できた
-
Dockerfileが出来上がってしまえば環境の再構築がVirtualBoxよりも早い
-
Go開発の環境構築がワンコマンドですむようになった
- git pull https://github.com/u1and0/dotfiles
- 初回はdotfilesをホームに置き換え
- 初回はneovimプラグインインストール
- :GoInstallBinariesで長時間待つ
↓ - docker pull u1and0/vim-goで長時間待つ
-
(ここから2020.4.30 update)
-
Go開発に限らずなんの環境でも自分のdotfilesが摘要済み、プラグインインストール済みの環境が整う
-
docker-composeを使えばますますラクさを実感できる
デメリット
- dotfilesが個人依存なので配布できる形で公開する意味はあるのか?dotfilesにinstallスクリプトも用意してあるし、ダブりじゃないか?
-
dotfiles更新の度にレイヤーの更新をする仕事が増えたコンテナ内でgit pullして適用する。気が向いたらイメージアップデートするときに親のu1and0/archlinuxイメージのdotfileをアップデートする。masterブランチにdotfilesの最新版を挙げておけばDockerhubでautomate buildを利用するには有料版にアップデートしないといけません。(2021.1.5 update)docker build --no-cache(適宜) -t u1and0/archlinux .
で自動的に更新できるので、結果的に仕事は楽になる。(2020.4.30 update) -
historyが残らないのがツラい。開発においては過去のコマンドも資産なので。>> docker-compose上で解決.docker-composeじゃなくてもdocker run -v
のボリュームで共有すれば解決すると思う(2020.4.30 update) -
historyを残すにはホストマシンとボリューム共有してhistoryファイルをリンクするとかcommitするとか一手間必要。(2020.4.30 update) - レイヤーが重い。ディスク容量を食いつぶす。VirtualBoxでさえディスク容量食いつぶしてるのに。これは最適化の余地あり
- ホストにもゲストにも同じバイナリ(基本的なgrepとかvimとか、/binとか/usr/bin下にあるようなやつら)があって「それってエコシステムなの?」と自問自答している
総評
(ここから2020.4.30 update)
- 使って1年以上経つけど、docker-compose使ってますますコンテナ開発環境が手放せなくなりました。
- k8sはフクザツすぎて勉強を断念しました。
-
multipassはポートフォワーディングのやり方がわからなくて止まっています。誰か教えてください。- multipassのポートフォワーディング記事化 → Windows上でLinux活動するための環境構築します