title: 基於 Docker 構建統一的開發環境
slug: build-development-environment-with-docker
date: 2021-06-27 18:56:23
thumbnail: ./images/cover/build-development-environment-with-docker.png
categories:
- Coding
tags: - Docker
- 開發環境
- Docker-Compose
前言
大多數人可能都遇到過這樣一個問題,在本地開發好功能後,部署到伺服器,或者其他人拉到本地接著開發時,會出現功能用不了的情況。
大多數時候是由於系統不同,依賴出現差異而導致的。因此,為了解決這個問題,基於 Docker 構建統一開發環境的需求便產生了。
使用 Docker 的好處
- 部署方便:平常要搭建環境常常需要耗費幾個小時,而且,對於團隊協作時來說,每有新人進來,都需要浪費這可以避免的時間,而且搭建環境時,也常常會產生的各種問題,導致專案程式碼執行異常。如果使用了 Docker 的話,只需最開始的人寫好開發容器,其他人只需要 pull 下來,即可完成專案環境的搭建,能有效避免無意義的時間浪費。
- 隔離性:我們時常會在一臺電腦部署多個專案環境,若是直接安裝的話,彼此間有可能會造成干擾,比如一個專案需要 Node.js 14,有的又需要 Node.js 12,若是直接在本機部署的話,總是不能共存的,而是用 Docker 的話,則可以避免該問題。Docker 還能確保每個應用程式只使用分配給它的資源(包括 CPU、記憶體和磁碟空間)。一個特殊的軟體將不會使用你全部的可用資源,要不然這將導致效能降低,甚至讓其他應用程式完全停止工作。
實現
安裝 Docker
Linux
我是用的是 Arch Linux,所以以下安裝方法是以 Arch Linux 為基礎,其他發行版也大同小異,只是換成其包管理工具而已。
# 設定國內映象站,國內提速用的,可選操作
$ sudo pacman-mirrors -i -c China -m rank
# 使用 Pacman 安裝 Docker
$ sudo pacman -S docker
# 建立 docker 使用者組。預設情況下,docker 命令會使用 Unix socket 與 Docker 引擎通訊。而只有 root 使用者和 docker 組的使用者才可以訪問 Docker 引擎的 Unix socket。出於安全考慮,一般 Linux 系統上不會直接使用 root 使用者。因此,更好地做法是將需要使用 docker 的使用者加入 docker 使用者組。
$ sudo groupadd docker
# 將當前使用者加入 docker 組,退出當前終端並重新登入後生效
$ sudo usermod -aG docker $USER
# 測試是否安裝成功
$ docker run --rm hello-world
Windows 10
Windows 10 下安裝 docker 比較簡單,有如下幾種方式:
手動下載安裝
點選以下 連結 下載 Docker Desktop for Windows。
下載好之後雙擊 Docker Desktop Installer.exe
開始安裝。
使用 winget 安裝
$ winget install Docker.DockerDesktop
執行
在 Windows 搜尋欄輸入 Docker 點選 Docker Desktop 開始執行。
Docker 啟動之後會在 Windows 工作列出現鯨魚圖示。
等待片刻,當鯨魚圖示靜止時,說明 Docker 啟動成功,之後你可以開啟 PowerShell/CMD/Windows Terminal 使用 Docker。
macOS
使用 Homebrew 安裝
Homebrew 的 Cask 已經支援 Docker Desktop for Mac,因此可以很方便的使用 Homebrew Cask 來進行安裝:
$ brew install --cask docker
手動下載安裝
如果需要手動下載,請點選以下 連結 下載 Docker Desktop for Mac。
請注意下載對應晶片型別的軟體,M1 和 Intel 晶片所對應的版本不通用。
如同 macOS 其它軟體一樣,安裝也非常簡單,雙擊下載的 .dmg 檔案,然後將那隻叫 Moby 的鯨魚圖示拖拽到 Application 資料夾即可(其間需要輸入使用者密碼)。
執行
從應用中找到 Docker 圖示並點選執行。
執行之後,會在右上角選單欄看到多了一個鯨魚圖示,這個圖示表明瞭 Docker 的執行狀態。
每次點選鯨魚圖示會彈出操作選單。
之後,你可以在終端透過命令檢查安裝後的 Docker 版本。
$ docker --version
編寫 Dockerfile
安裝完 Docker 之後,接下來我們便可以來編寫我們自己的專案開發環境了。本文將以前端開發環境為例,構建 Dockerfile。
包含環境:
node.js 14.17
npm 6.14
yarn 1.22
# 前端開發中,時常需要使用 shell 命令,而有一個較為完整的環境比較重要,因此選擇了使用 ubuntu 作為基礎,若在意容器大小的話,可自行選擇適用的基礎映象
FROM ubuntu
MAINTAINER Caster "moecasts.caster@gmail.com"
# 設定環境變數
ENV DEBIAN_FRONTEND noninteractive
# 設定時區
ARG TZ=Asia/Shanghai
ENV TZ ${TZ}
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 用 root 使用者操作
USER root
# 更換阿里雲源,在國內可以加快速度
RUN sed -i "s/security.ubuntu.com/mirrors.aliyun.com/" /etc/apt/sources.list && \
sed -i "s/archive.ubuntu.com/mirrors.aliyun.com/" /etc/apt/sources.list && \
sed -i "s/security-cdn.ubuntu.com/mirrors.aliyun.com/" /etc/apt/sources.list
RUN apt-get clean
# 更新源,安裝相應工具
RUN apt-get update && apt-get install -y \
zsh \
vim \
wget \
curl \
python \
git-core
# 安裝 zsh,以後進入容器中時,更加方便地使用 shell
RUN git clone https://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh \
&& cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc \
&& git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions \
&& git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting \
&& sed -i 's/^plugins=(/plugins=(zsh-autosuggestions zsh-syntax-highlighting z /' ~/.zshrc \
&& chsh -s /bin/zsh
# 建立 me 使用者
RUN useradd --create-home --no-log-init --shell /bin/zsh -G sudo me
RUN adduser me sudo
RUN echo 'me:password' | chpasswd
# 為 me 安裝 omz
USER me
RUN git clone https://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh \
&& cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc \
&& git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions \
&& git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting \
&& sed -i 's/^plugins=(/plugins=(zsh-autosuggestions zsh-syntax-highlighting z /' ~/.zshrc
# 安裝 nvm 和 node
ENV NVM_DIR /home/me/.nvm
ENV NODE_VERSION v14
RUN mkdir -p $NVM_DIR && \
curl -o- https://gitee.com/mirrors/nvm/raw/master/install.sh | bash \
&& . $NVM_DIR/nvm.sh \
&& nvm install ${NODE_VERSION} \
&& nvm use ${NODE_VERSION} \
&& nvm alias ${NODE_VERSION} \
&& ln -s `npm bin --global` /home/me/.node-bin \
&& npm install --global nrm \
&& nrm use taobao
USER me
RUN echo '' >> ~/.zshrc \
&& echo 'export NVM_DIR="$HOME/.nvm"' >> ~/.zshrc \
&& echo '[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm' >> ~/.zshrc
# 安裝 yarn
RUN curl -o- -L https://yarnpkg.com/install.sh | bash; \
echo '' >> ~/.zshrc && \
echo 'export PATH="$HOME/.yarn/bin:$PATH"' >> ~/.zshrc
# Add NVM binaries to root's .bashrc
USER root
RUN echo '' >> ~/.zshrc \
&& echo 'export NVM_DIR="/home/me/.nvm"' >> ~/.zshrc \
&& echo '[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm' >> ~/.zshrc
USER root
RUN echo '' >> ~/.zshrc \
&& echo 'export YARN_DIR="/home/me/.yarn"' >> ~/.zshrc \
&& echo 'export PATH="$YARN_DIR/bin:$PATH"' >> ~/.zshrc
# Add PATH for node
ENV PATH $PATH:/home/me/.node-bin
# Add PATH for YARN
ENV PATH $PATH:/home/me/.yarn/bin
# 刪除 apt/lists,可以減少最終映象大小,詳情見:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#general-guidelines-and-recommendations
USER root
RUN rm -rf /var/lib/apt/lists/*
WORKDIR /var/www
編寫完 Dockerfile 後,構建即可:
docker build -t frontend/react:v1 .
構建完之後可以直接執行:
# 以 me 身份執行,推薦方式
docker run --user=me -it frontend/react:v1 /bin/zsh
# 以 root 角色執行
docker run -it frontend/react:v1 /bin/zsh
編寫 docker-compose.yml
在開發時,我們尋常需要多個容器配合使用,比如需要配合 mysql 或其他容器使用時,使用 docker-compose.yml 可以更好的組織他們。
version: '2'
services:
react:
build:
context: .
dockerfile: react/Dockerfile
tty: true
ports:
- 30000:3000
volumes:
- ./react/www:/var/www
networks:
- frontend
mysql:
image: mysql:5.7
ports:
- 33060:3306
volumes:
- ./mysql/data:/var/lib/mysql
- ./mysql/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
environment:
- MYSQL_ROOT_PASSWORD=password
networks:
- frontend
# 將容器置於同一 networks 即可直接透過容器名訪問
networks:
frontend:
driver: bridge
啟動容器
編寫玩上述 Dockerfile
和 docker-compose.yml
後,即可愉快的開始開發了!
# 進入 docker-compose.yml 所在目錄
cd frontend
# 後臺啟動 docker-compose.yml 中所有容器,若容器沒有構建則會先構建
docker compose up -d
# 進入 react 容器中,以便命令列互動
docker compose exec --user=me react /bin/zsh
為了測試容器間是否能相互訪問,可以使用編寫如下檔案,資料庫需自行建立:
// index.js
const mysql = require('mysql')
const connection = mysql.createConnection({
host: 'mysql',
user: 'root',
password: 'password',
database: 'test',
})
connection.connect();
connection.query(`SELECT * FROM users`, function (error, results, fields) {
if (error) throw error;
console.log(results)
})
connection.end();
之後執行,即可看到結果:
$ node index.js
[ RowDataPacket { id: 1, name: 'Caster' } ]
總結
使用 Docker 來搭建開發環境十分方便,一次搭建,即可在許多機器上多次使用,即使是要重灌系統,也不必在重複配置。
如不喜歡寫 Dockerfile 的話,也可以直接開啟一個容器,然後進入容器配置完後,使用 docker save/export 匯出即可。
原始碼:github.com/MoeCasts/dockerfile-fro...
本文首發於 個人部落格
本作品採用《CC 協議》,轉載必須註明作者和本文連結