VSCode云端開發(fā)環(huán)境搭建 (Remote-Containers)

為什么要使用云端開發(fā)環(huán)境

2019年5月份,微軟發(fā)布一組VSCode插件“Remote-Development”。它可以讓開發(fā)者在VSCode中直接訪問遠(yuǎn)程的目錄進(jìn)行開發(fā)工作。這樣我們的代碼和開發(fā)環(huán)境就可以和終端電腦分離了 任斋,并且可以隨意在遠(yuǎn)端搭建多個(gè)不同的開發(fā)環(huán)境隨時(shí)切換盈包。 聽起來是不是有點(diǎn)小激動(dòng)呢?

其實(shí)遠(yuǎn)程開發(fā)的模式并不新鮮挡逼。很久以前我就通過FTP或SFTP鏈接,直接在服務(wù)器上進(jìn)行開發(fā)腻豌。但這種方式成本比較高家坎,需要一臺(tái)遠(yuǎn)程服務(wù)器支持,而且多人同時(shí)使用的時(shí)候可能產(chǎn)生版本依賴的沖突吝梅。這幾年容器技術(shù)和應(yīng)用場(chǎng)景猶如獲得神速力的加持般飛速發(fā)展虱疏。結(jié)合容器技術(shù)可以有效的將不同的開發(fā)環(huán)境進(jìn)行區(qū)隔,并且以容器為單位苏携,進(jìn)行復(fù)制做瞪、遷移變得前所未有的簡(jiǎn)單。

所以使用云端開發(fā)環(huán)境有以下幾個(gè)優(yōu)點(diǎn):

  • 有多語(yǔ)言右冻、多環(huán)境的開發(fā)需求時(shí)装蓬,可以避免對(duì)本機(jī)環(huán)境的污染
  • 方便遷移、復(fù)制纱扭,甚至可以在小組內(nèi)對(duì)同樣的環(huán)境需求進(jìn)行打包牍帚、分發(fā)
  • 在局域網(wǎng)內(nèi)搭建開發(fā)服務(wù)器可以節(jié)省筆記本的負(fù)載,更加有效的提升筆記本的使用效率

先介紹一下 Remote-Developement 插件組

微軟發(fā)布了3個(gè)遠(yuǎn)程開發(fā)插件乳蛾,分別是 “Remote-SSH”暗赶、“Remote-Containers”、“Remote-WSL”肃叶,并將它們放入了插件包 “Remote-Developement” 中一同發(fā)布蹂随。

  • Remote-SSH:通過ssh,連接遠(yuǎn)程服務(wù)器因惭。(平平無奇)
  • Remote-Containers:連接Docker容器岳锁。(非常驚艷)
  • Remote-WSL:連接“Windows Subsystem for Linux”(就是在Win10中安裝的Linux)。

今天我們著重介紹如何使用“Remote-Containers”蹦魔,開始吧激率。

準(zhǔn)備Docker環(huán)境

環(huán)境說明

我的桌面系統(tǒng)是MacOS,和Windows的差異版姑,小伙伴們可以自行腦補(bǔ)柱搜。

在安裝Docker的時(shí)候,我們并不需要安裝官網(wǎng)提供的標(biāo)準(zhǔn)安裝包剥险,因?yàn)槟前?code>Docker Engine和Docker Client

所以我們需要安裝的是docker-toolbox宪肖。MacOS可以通過brew search docker-toolbox找到表制,其他系統(tǒng)可以通過github下載 https://github.com/docker/toolbox/releases

$ brew cask install docker-toolbox     

docker-toolbox包含以下幾部分內(nèi)容

  • docker-cli : 客戶端命令行,目前的版本是19.03.1
  • docker-machine : 可以在本機(jī)啟動(dòng)用于Docker Engine虛擬機(jī)并管理他們
  • docker-compose : docker提供的編排工具健爬,支持compose文件,這個(gè)并不常用么介。
  • Kitematic : Docker的客戶端GUI娜遵,官方已經(jīng)廢棄了。
  • Boot2Docker ISO : 用于創(chuàng)建Docker Engine虛擬機(jī)的鏡像壤短。由于包中的這個(gè)版本并不是最新的设拟,所以創(chuàng)建虛擬機(jī)的時(shí)候可能會(huì)需要重新下載。
  • VirtualBox : 虛擬機(jī)

創(chuàng)建Docker Machine

$ docker-machine create --driver virtualbox \
    --virtualbox-cpu-count 2 \
    --virtualbox-memory 2048 \
    default
Running pre-create checks...
Creating machine...
(default) Copying ${HOME}/.docker/machine/cache/boot2docker.iso to ${HOME}/.docker/machine/machines/default/boot2docker.iso...
(default) Creating VirtualBox VM...
(default) Creating SSH key...
(default) Starting the VM...
(default) Check network to re-create if needed...
(default) Waiting for an IP...
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with boot2docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env default

創(chuàng)建成功后久脯,連接到Machine

$ eval $(docker-machine env default)
$ docker version

Client: Docker Engine - Community
 Version:           19.03.1
 API version:       1.40
 Go version:        go1.12.5
 Git commit:        74b1e89
 Built:             Thu Jul 25 21:18:17 2019
 OS/Arch:           darwin/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.5
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.12
  Git commit:       633a0ea838
  Built:            Wed Nov 13 07:28:45 2019
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.2.10
  GitCommit:        b34a5c8af56e510852c35414db4c1f4fa6172339
 runc:
  Version:          1.0.0-rc8+dev
  GitCommit:        3e425f80a8c931f88e6d94a8c831b9d5aa481657
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683
$
$ # OK,連接成功!

從官方Sample開始

先取得官方的Sample項(xiàng)目纳胧。在github上查找 vscode-remote-try 我們可以找到一堆項(xiàng)目,都是微軟官方提供的不同語(yǔ)言環(huán)境的Sample帘撰。這里我們用 vscode-remote-try-python 作為例子跑慕。

$ git clone https://github.com/microsoft/vscode-remote-try-python.git
$ cd vscode-remote-try-python/
$ 
$ # 打開項(xiàng)目目錄
$ /Applications/Visual\ Studio\ Code.app/Contents/MacOS/Electron ./
$ # windows 使用命令 "code .\"

Sample的目錄結(jié)構(gòu)

[workspace]
|- .devcontainer :              開發(fā)環(huán)境配置目錄
|  |- devcontainer.json :       環(huán)境配置文件
|  |- Dockerfile :              環(huán)境的Docker鏡像生成文件
|- .vscode :                    vscode使用的配置文件(容器端使用)
|  |- launch.json :             debuger 配置文件(容器端使用)
|- static :                     Sample項(xiàng)目的靜態(tài)頁(yè)面目錄
|  |- index.html :              Sample項(xiàng)目首頁(yè)
|- .gitattributes :             git 文件屬性定義
|- .gitignore :                 git 忽略文件
|- app.py :                     flask項(xiàng)目入口
|- LICENSE
|- README.md
|- requirements.txt :           項(xiàng)目的環(huán)境所需要的python模塊,通過pip安裝

下面我們著重介紹 devcontainer.jsonDockerfile兩個(gè)文件

.devcontainer/devcontainer.json

這個(gè)文件是用于啟動(dòng)開發(fā)容器的配置摧找。點(diǎn)擊查看官方文檔核行。下面我們介紹一下配置屬性。

屬性 類型 描述
通用參數(shù)
name 字符串 容器顯示名稱
extensions 數(shù)組 需要安裝到容器中的vscode擴(kuò)展蹬耘。 缺省值"[]"
settings json對(duì)象 添加到容器中的vscode settings.json
postCreateCommand 字符串,數(shù)組 容器創(chuàng)建后第一次啟動(dòng)時(shí)執(zhí)行的一組命令芝雪。命令執(zhí)行目錄是容器中workspaceFolder指定的目錄。多條命令之間使用&&進(jìn)行連接综苔。 缺省值 none
devPort 整數(shù) 允許給vscode server指定一個(gè)端口绵脯。缺省為一個(gè)隨機(jī)可用端口。
Dockerfile或Image
image 字符串 必填 使用已存在鏡像時(shí)必填休里。 vscode會(huì)使用鏡像名稱來創(chuàng)建開發(fā)容器蛆挫。
dockerFile 字符串 必填 使用Dockerfile時(shí)必填。 指定一個(gè)用來生成Docker鏡像的Dockerfile文件妙黍。路徑相對(duì)于devcontainer.json文件悴侵。 可以在這個(gè)地址找到各種Dockerfile樣例。
context 字符串 指定運(yùn)行docker build命令時(shí)的上下文目錄拭嫁。 路徑是基于devcontainer.json文件的相對(duì)路徑可免。 缺省值"."
appPort 整數(shù),字符串,數(shù)組 容器運(yùn)行時(shí)發(fā)布到Host的端口。多個(gè)端口用數(shù)組表示做粤。 缺省值"[]"
workspaceMount 字符串 覆蓋缺省的mount參數(shù)浇借。語(yǔ)法參見Docker文檔Docker CLI --mount flag。 可以使用${localWorkspaceFolder}引用本地的工作區(qū)目錄怕品,或使用${env:VARNAMEHERE}應(yīng)用環(huán)境變量
workspaceFolder 字符串 設(shè)置vscode連接到容器后缺省的工作目錄妇垢。 通常結(jié)合workspaceMount屬性使用。
runArgs 數(shù)組 運(yùn)行容器時(shí)的命令行參數(shù)Docker CLI arguments。 缺省值"[]"闯估。 可以使用${localWorkspaceFolder}引用本地的工作區(qū)目錄灼舍,或使用${env:VARNAMEHERE}應(yīng)用環(huán)境變量
overrideCommand 布爾 告訴容器在啟動(dòng)時(shí)是否執(zhí)行命令 /bin/sh -c "while sleep 1000; do :; done",用以覆蓋缺省的啟動(dòng)執(zhí)行命令涨薪。 缺省值"true"骑素。
shutdownAction 枚舉: none,stopContainer 指定在vscode斷開連接或者關(guān)閉時(shí),是否停止容器刚夺。 缺省值"stopContainer"
Docker Compose
dockerComposeFile 字符串,數(shù)組 必填 指定一個(gè)Docker Compose文件献丑,路徑相對(duì)于devcontainer.json文件。 當(dāng)需要擴(kuò)展Docker Compose配置時(shí)侠姑,可以使用數(shù)組创橄。數(shù)組的順序和重要,后面的文件內(nèi)容會(huì)覆蓋之前的設(shè)置结借。 缺省的.env文件會(huì)在項(xiàng)目的根路徑下尋找筐摘,但可以通過Docker Compose文件中的env_file指定另外的路徑。
service 字符串 必填 指定啟動(dòng)后vscode連接哪個(gè)service船老。
runServices 數(shù)組 指定Docker Compose文件中的哪些services需要啟動(dòng)咖熟。同時(shí)在斷開連接后,這些services將會(huì)根據(jù)shutdownAction的設(shè)置決定是否關(guān)閉柳畔。 缺省值為所有的services馍管。
workspaceFolder 字符串 連接到容器后進(jìn)入的工作目錄。缺省值"/"
shutdownAction 枚舉: none,stopCompose 指定在vscode斷開連接或者關(guān)閉時(shí)薪韩,是否停止容器确沸。 缺省值"stopCompose"

那么我們看看Sample中的.devcontainer文件內(nèi)容。(為了方便顯示俘陷,我過濾的原文件中的注釋)

{
    "name": "Python Sample",
    "dockerFile": "Dockerfile",

    "appPort": [9000],

    "runArgs": ["-u", "vscode"],

    "settings": { 
        "terminal.integrated.shell.linux": "/bin/bash",
        "python.pythonPath": "/usr/local/bin/python",
        "python.linting.pylintEnabled": true,
        "python.linting.pylintPath": "/usr/local/bin/pylint",
        "python.linting.enabled": true
    },

    "postCreateCommand": "sudo pip install -r requirements.txt",

    "extensions": [
        "ms-python.python"
    ]
}

根據(jù)這個(gè)配置罗捎,我們可以知道。

  • "dockerFile": 開發(fā)容器根據(jù)Dockerfile創(chuàng)建拉盾。Dockerfile的路徑是.devcontainer/Dockerfile
  • "appPort": 容器啟動(dòng)時(shí)publish9000端口到Host桨菜。這里的Host就是我們創(chuàng)建的Docker Machine。
  • "runArgs": 容器啟動(dòng)時(shí)捉偏,使用vscode用戶進(jìn)行登錄倒得。(vscode用戶在Dockerfile中創(chuàng)建)
  • "settings": vscode連接到容器后,會(huì)應(yīng)用如下配置:
    • 終端使用bash
    • 指定python命令的路徑
    • 啟用pylint
  • "postCreateCommand": 容器啟動(dòng)時(shí)安裝requirements.txt文件中的python modules夭禽。
  • 在容器中安裝vscode擴(kuò)展霞掺,"ms-python.python"

上述內(nèi)容基本上是在說,容器啟動(dòng)時(shí)需要做的事情讹躯。
這里需要強(qiáng)調(diào)一點(diǎn): Remote-Containers是通過"鏡像"來管理環(huán)境的 菩彬。容器只是運(yùn)行時(shí)環(huán)境缠劝,容器是可以隨時(shí)刪除、重建挤巡,并同時(shí)要保證環(huán)境是持續(xù)可用的剩彬。
所以酷麦,容器運(yùn)行時(shí)的配置都放到了devcontainer.josn文件中矿卑。

下面我們來看看鏡像的生成 - Dockerfile

.devcontainer/Dockfile

關(guān)于Dockerfile的格式,參見官方文檔沃饶。
看看Sample中的內(nèi)容母廷。


# 基于官方的"python:3"鏡像
FROM python:3

# 切換到非交互模式避免警告
ENV DEBIAN_FRONTEND=noninteractive

# 指定創(chuàng)建的非root用戶
ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID

# 首先更新系統(tǒng)
RUN apt-get update \
    # 安裝vscode server需要的基礎(chǔ)軟件
    && apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
    && apt-get -y install git procps lsb-release \
    #
    # 安裝 pylint
    && pip --disable-pip-version-check --no-cache-dir install pylint \
    #
    # 創(chuàng)建一個(gè)非root用戶 (為啥需要這個(gè),請(qǐng)看 - https://aka.ms/vscode-remote/containers/non-root-user)
    && groupadd --gid $USER_GID $USERNAME \
    && useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
    # [可選] 添加sudo命令
    && apt-get install -y sudo \
    # 將新創(chuàng)建的非root用戶添加到sudoers
    && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
    && chmod 0440 /etc/sudoers.d/$USERNAME \
    #
    # 打掃衛(wèi)生
    && apt-get autoremove -y \
    && apt-get clean -y \
    && rm -rf /var/lib/apt/lists/*

# Switch back to dialog for any ad-hoc use of apt-get
ENV DEBIAN_FRONTEND=

依靠上述兩個(gè)文件糊肤,vscode會(huì)創(chuàng)建指定的鏡像琴昆,和容器。并連接容器進(jìn)入工作區(qū)馆揉。
但由于在墻內(nèi)业舍,我們安裝的速度會(huì)比較慢,所以我們需要隨上述文件做些修改升酣。提高下載速度舷暮。

更改安裝源,提高下載速度

修改Dockerfile

...
# 將debian的更新源改為aliyun的鏡像
RUN sed -i -e 's/\w\+\.debian\.org/mirrors.aliyun.com/g' /etc/apt/sources.list \
    # 首先更新系統(tǒng)
    && apt-get update \
...
    # 安裝 pylint (使用aliyun鏡像)
    && pip --disable-pip-version-check --no-cache-dir install pylint -i https://mirrors.aliyun.com/pypi/simple/ \

...

修改devcontainer.json

{
  "postCreateCommand": "sudo pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/",
}

現(xiàn)在配置都已經(jīng)準(zhǔn)備好了噩茄,下面我們需要連接安裝好的Docker Engine

現(xiàn)在需要通過vscode連接Docker Engine

vscode連接Docker Engine是通過settings進(jìn)行配置的下面。我們當(dāng)然可以直接修改全局的settings.json但這樣會(huì)污染全局參數(shù)。我建議通過workspace級(jí)別的settings進(jìn)行設(shè)置绩聘。
我們要?jiǎng)?chuàng)建一個(gè)新的workspace沥割。
在Sample項(xiàng)目的目錄下,新建一個(gè)文件凿菩,命名為python.code-workspace,內(nèi)容如下:

{
    "folders":[
        {
            "name":"Python Sample",
            "path":"."
        }
    ],
    "settings": {
        "docker.host": "${DOCKER_HOST}",
        "docker.tlsVerify": "1",
        "docker.certPath": "${DOCKER_CERT_PATH}"
    }
}

執(zhí)行"docker-machine env default"會(huì)輸出Docker Machine的連接地址和證書目錄机杜。

export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://xxx.xxx.xxx.xxx:2376"
export DOCKER_CERT_PATH="/xxx..."
export DOCKER_MACHINE_NAME="default"
# Run this command to configure your shell: 
# eval $(docker-machine env default)

使用DOCKER_HOST,DOCKER_CERT_PATH對(duì)應(yīng)的值填入上面的json文件。

然后打開Remote-Containers擴(kuò)展衅谷,選擇Reopen in Container

vscode-remote-containers

圖解Remote-Containers的部署過程

vscode連接容器的過程中都做了什么工作呢椒拗?我們可以分析一下連接過程輸出的日志信息。
總結(jié)后的內(nèi)容參見下圖会喝。

Remote-Containers的部署過程

1. 連接到Docker Engine:

vscode通過在python.code-workspace文件中的三項(xiàng)配置連接Docker Engine陡叠。

  • "docker.host": 服務(wù)器地址及端口
  • "docker.tlsVerify": 使用啟動(dòng)TLS驗(yàn)證
  • "docker.certPath": 啟動(dòng)TLS的話,證書存放的路徑

由于我們是使用Docker Machine創(chuàng)建的服務(wù)器和連接肢执,證書的生成和配置docker-machine命令已經(jīng)幫我們做好了枉阵。

2. 構(gòu)建鏡像

再?gòu)?qiáng)調(diào)一次 Remote-Containers是通過"鏡像"來管理環(huán)境的

  • Dockerfile文件通過devcontainer.json中的"Dockerfile"屬性指定预茄。
    如果使用Compose文件兴溜,通過"dockerComposeFile"屬性指定侦厚。
  • 鏡像名稱:
    缺省情況下,vscode會(huì)根據(jù)環(huán)境生成一個(gè)鏡像名稱拙徽,格式為vsc-<工作區(qū)目錄名>-<UUID>刨沦。
    我們可以通過在devcontainer.json中添加"image"屬性,來指定一個(gè)具體的鏡像名稱膘怕。
    注1:如果"image"對(duì)應(yīng)的鏡像已經(jīng)存在想诅,可以不指定"Dockerfile"屬性。
    注2:如果同時(shí)指定了"image"岛心,"Dockerfile",vscode的語(yǔ)法檢查會(huì)給出"warn"来破。不要擔(dān)心,這個(gè)可以忽略忘古。
  • build時(shí)的上下文目錄:
    缺省為.devcontainer目錄徘禁。
    可以通過devcontainer.json"context"`屬性指定。
3. 創(chuàng)建并啟動(dòng)容器
  • 目錄映射
    缺省情況下髓堪,vscode會(huì)將<本地工作區(qū)的目錄>映射到容器的"/workspace"目錄送朱。
    這里需要強(qiáng)調(diào)一點(diǎn),由于docker run實(shí)際上是在服務(wù)器端執(zhí)行的干旁,所以<本地工作區(qū)的目錄>指的是服務(wù)器端的路徑驶沼。
    docker-machine命令創(chuàng)建的虛擬機(jī)會(huì)自動(dòng)將本地的"/Users"目錄共享到服務(wù)器的"/Users"(MacOS上述"/Users",其他系統(tǒng)可能有所不同)。所以<本地工作區(qū)的目錄>在本地和服務(wù)器上同樣有效疤孕。

    如果服務(wù)器不是由docker-machine創(chuàng)建的商乎,那么可以在devcontainer.json中指定"workspaceMount"屬性。
    例如:
    先創(chuàng)建一個(gè)卷docker volume create v-sample-python
    然后設(shè)置"workspaceMount": "type=volume,source=v-sample-python,destination=/workspace"
    這樣容器就掛載了卷祭阀,從而避免的本地目錄的映射鹉戚。
    這種操作的問題是,在容器中對(duì)文件的修改专控,不會(huì)直接和本地文件同步抹凳。我們需要使用git或其他SCM工具來管理代碼。

  • 端口映射
    在Sample中"appPort"屬性伦腐,指定了映射到服務(wù)器Host的端口赢底。我們查看一下:

    $ docker ps
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                      NAMES
    8588365e7f73        sample-python       "/bin/sh -c 'echo Co…"   8 minutes ago       Up 7 minutes        127.0.0.1:9000->9000/tcp   sample-python     
    

    9000端口雖然打開了,但綁定的是127.0.0.1地址柏蘑,這根本沒啥用嘛(安裝Docker Desktop版除外)幸冻。
    將屬性值改為"appPort": ["0.0.0.0:9000:9000"]即可。

  • 啟動(dòng)后執(zhí)行命令
    vscode有一個(gè)標(biāo)準(zhǔn)的啟動(dòng)后執(zhí)行命令/bin/sh -c "while sleep 1000; do :; done"咳焚。這行命令讓容器的主進(jìn)程始終循環(huán)洽损。這樣可以保證容器不會(huì)自動(dòng)停止。關(guān)于容器如何不停止的問題請(qǐng)看 Docker初學(xué)者問題 - 如何讓容器啟動(dòng)后不會(huì)自動(dòng)停止
    可以通過設(shè)置屬性"overrideCommand"=false來禁止vscode使用這一命令革半。同時(shí)在"runArgs"屬性中定制自己的啟動(dòng)命令碑定。

  • 容器中的用戶
    Dockerfile中創(chuàng)建了一個(gè)用戶vscode流码,在容器啟動(dòng)時(shí)通過"runArgs"屬性的"-u", "vscode"指定連接到容器的缺省用戶。為什么要?jiǎng)?chuàng)建非root用戶?可以閱讀說明 Adding a non-root user to your dev container延刘。
    這里我簡(jiǎn)要的說明一下漫试,很多基礎(chǔ)鏡像缺省用戶是root,當(dāng)容器中使用root用戶創(chuàng)建文件時(shí)碘赖,文件的owner也是root這有可能導(dǎo)致本地的用戶無法訪問這些文件驾荣。具體根據(jù)目錄映射的形式不同我們分為3種情況:

    1. vscode連接Docker Desktop安裝的Docker Engine。
      這種情況下崖疤,缺省docker run會(huì)將本地的工作區(qū)目錄mount到容器中秘车,如果容器使用的是root用戶典勇,那么容器中創(chuàng)建的文件也相當(dāng)于本機(jī)root創(chuàng)建的文件劫哼。而本機(jī)的操作用戶(一般來說是非root用戶)無法訪問。
      這時(shí)割笙,就需要根據(jù)本機(jī)的操作用戶的idgroupidDockerfile中創(chuàng)建對(duì)應(yīng)的用戶权烧,來解決這一問題褐桌。
      本地用戶的idgroupid可以通過"id -u","id -g"命令查看骗随。
    2. vscode連接Docker Machine創(chuàng)建的虛擬機(jī)
      這種情況下,容器映射的目錄是虛擬機(jī)中的目錄被丧,而虛擬機(jī)的目錄時(shí)通過VirtualBox來共享的本機(jī)目錄乱顾,由于VirtualBox的共享會(huì)使用本機(jī)的當(dāng)前操作用戶來作為訪問共享目錄的用戶板祝。所以無論容器中使用什么用戶,都不會(huì)產(chǎn)生問題走净。
    3. 使用卷或遠(yuǎn)程服務(wù)的目錄做mount
      這種情況與本機(jī)的目錄沒有任何關(guān)系券时,所以不會(huì)產(chǎn)生問題。
4. 在容器中安裝vscode擴(kuò)展插件

vscode在連接到容器的環(huán)境后伏伯,會(huì)根據(jù)不同的容器加載不同的插件橘洞。這些插件是安裝在容器中的,不會(huì)污染本機(jī)的插件環(huán)境说搅。
安裝哪些插件由devcontianer.json中的"extensions"屬性指定炸枣。
插件會(huì)安裝到容器中的${HOME}/.vscode-server/extensions目錄。

5. 安裝 "VS Code Server"

"VS Code Server"是做什么用的弄唧?官網(wǎng)有張圖可以說明适肠。


Architecture summary

按照我的理解,"VS Code Server"是用來管理容器中的插件并使其可以在本地的vscode中使用候引。

開發(fā)過程

重新構(gòu)建鏡像

由于樣例中使用的是pythondebian鏡像侯养。個(gè)人感覺鏡像比較大,安裝慢背伴。我比較喜歡Alpine鏡像沸毁。python本身有3.7.5-alpine3.10鏡像峰髓,但我更喜歡直接使用alpine:3.10,因?yàn)檠b完python環(huán)境后比官方的Python或小那么一點(diǎn)點(diǎn)息尺。

添加alpine.Dockerfile

內(nèi)容如下

FROM alpine:3.10

ENV DEBIAN_FRONTEND=noninteractive

ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID

RUN sed -i -e 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/' /etc/apk/repositories\
    && apk --update add --no-cache \
        libuuid \
        gcc \
        libc-dev \
        linux-headers \
        make  \
        automake   \
        g++  \
        python3-dev \
        sudo \
        bash \
        git \
        curl \
        python3 \
    && curl https://bootstrap.pypa.io/get-pip.py| python3 - \
    && pip --disable-pip-version-check --no-cache-dir install pylint -i https://mirrors.aliyun.com/pypi/simple/ \
    && addgroup -g $USER_GID $USERNAME \
    && adduser -s /bin/bash -u $USER_UID -G $USERNAME -D $USERNAME \
    && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
    && chmod 0440 /etc/sudoers.d/$USERNAME

VOLUME [ "/workspace" ]

ENV DEBIAN_FRONTEND=


### 修改`devcontainer.json`
```json
{
  "dockerFile": "alpine.Dockerfile",
  "settings": { 
    "python.pythonPath": "/usr/bin/python3",
    "python.linting.pylintPath": "/usr/bin/pylint",
  }

啟動(dòng)Sample項(xiàng)目

啟動(dòng)容器后進(jìn)入flask項(xiàng)目目錄携兵。然后啟動(dòng)開發(fā)進(jìn)程。

$ FLASK_ENV=development flask run --host 0.0.0.0 --port 9000
 * Environment: development
 * Debug mode: on
 * Running on http://0.0.0.0:9000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 320-680-031

切換到本地筆記本搂誉,查看一下Docker主機(jī)的IP徐紧,由于我們使用Docker Machine建立的主機(jī),可以通過下面命令查看炭懊。

$ docker-machine ls
NAME      ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER     ERRORS
default   *        virtualbox   Running   tcp://192.168.99.122:2376           v19.03.5  

192.168.99.122就是Docker主機(jī)IP了并级。在瀏覽器訪問http://192.168.99.122:9000

由于之前在devcontainer.json文件中配置了"appPort": ["0.0.0.0:9000:9000"],所以容器在主機(jī)上映射了9000端口侮腹。
但這種配置在多人共享一臺(tái)Docker主機(jī)嘲碧,或者同時(shí)調(diào)試多個(gè)環(huán)境并產(chǎn)生端口沖突時(shí)會(huì)比較麻煩。
那么下面我介紹一下Forward端口

Forward端口

延續(xù)上一小節(jié)的環(huán)境父阻,我們?cè)谌萜髦袉?dòng)了開發(fā)進(jìn)程愈涩,開放的9000端口。現(xiàn)在我們做如下操作

  1. devcontainer.json中刪除"appPort"屬性
  2. 在命令行中使用docker rm -f sample-python刪除容器
  3. 重新在容器中啟動(dòng)項(xiàng)目
  4. 點(diǎn)擊左下角狀態(tài)欄綠色的部分
  5. 在出現(xiàn)命令菜單中選擇Remote-Containers: Forward Port from Container...
  6. 在出現(xiàn)的下一步的菜單中選擇Forwarding 9000
  7. 在瀏覽器打開http://localhost:9000地址就可以看到頁(yè)面了加矛。

停止Forward

  1. 點(diǎn)擊左下角狀態(tài)欄綠色的部分
  2. 在出現(xiàn)命令菜單中選擇Remote-Containers: Forward Port from Container...
  3. 在出現(xiàn)的下一步的菜單中選擇Stop Forwarding 9000->9000
  4. 就可以取消端口轉(zhuǎn)發(fā)

Forward端口的好處是不會(huì)占用Docker主機(jī)的端口資源

如果兩個(gè)容器環(huán)境同時(shí)需要Forward同樣的端口怎么辦么履婉?
vscode在Forward的時(shí)候,如果發(fā)現(xiàn)本機(jī)端口被占用斟览,則會(huì)隨機(jī)找一個(gè)可用端口Fowrard到容器中

程序調(diào)試

在sample項(xiàng)目中有一個(gè)文件.vscode/launch.josn這個(gè)就是調(diào)試配置文件毁腿。sample中已經(jīng)有了Flask的配置內(nèi)容。我們將其中"FLASK_APP"項(xiàng)修改成準(zhǔn)確的路徑指向app.py苛茂。然后啟動(dòng)調(diào)試進(jìn)程已烤。

Remote-Containers的調(diào)試過程-step

啟動(dòng)進(jìn)程后我們?cè)?code>app.py的hello()方法中加入斷點(diǎn)。然后在瀏覽器訪問http://127.0.0.1:9000(別忘了Forward端口)味悄。
這是你應(yīng)該可以看到草戈,vscode停在了斷點(diǎn)處。

到此為止VSCode使用Remote-Containers連接Docker容器的過程基本介紹完畢了侍瑟。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末唐片,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子涨颜,更是在濱河造成了極大的恐慌费韭,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件庭瑰,死亡現(xiàn)場(chǎng)離奇詭異星持,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)弹灭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門督暂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來揪垄,“玉大人,你說我怎么就攤上這事逻翁〖⑴” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵八回,是天一觀的道長(zhǎng)酷愧。 經(jīng)常有香客問我,道長(zhǎng)缠诅,這世上最難降的妖魔是什么溶浴? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮管引,結(jié)果婚禮上士败,老公的妹妹穿的比我還像新娘。我一直安慰自己汉匙,他們只是感情好拱烁,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著噩翠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪邦投。 梳的紋絲不亂的頭發(fā)上伤锚,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音志衣,去河邊找鬼屯援。 笑死,一個(gè)胖子當(dāng)著我的面吹牛念脯,可吹牛的內(nèi)容都是我干的狞洋。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼绿店,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼吉懊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起假勿,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤借嗽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后转培,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恶导,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年浸须,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惨寿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邦泄。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖裂垦,靈堂內(nèi)的尸體忽然破棺而出虎韵,到底是詐尸還是另有隱情,我是刑警寧澤缸废,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布包蓝,位于F島的核電站,受9級(jí)特大地震影響企量,放射性物質(zhì)發(fā)生泄漏测萎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一届巩、第九天 我趴在偏房一處隱蔽的房頂上張望硅瞧。 院中可真熱鬧,春花似錦恕汇、人聲如沸腕唧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)枣接。三九已至,卻和暖如春缺谴,著一層夾襖步出監(jiān)牢的瞬間但惶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工湿蛔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留膀曾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓阳啥,卻偏偏與公主長(zhǎng)得像添谊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子察迟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 五斩狱、Docker 端口映射 無論如何,這些 ip 是基于本地系統(tǒng)的并且容器的端口非本地主機(jī)是訪問不到的卷拘。此外喊废,除了...
    R_X閱讀 1,751評(píng)論 0 7
  • 讓博客Docker化,輕松上手Docker Docker是一個(gè)有趣的技術(shù)栗弟,在過去的兩年已經(jīng)從一個(gè)想法變成了全世界的...
    喵喵唔的老巢閱讀 339評(píng)論 0 0
  • 《Docker從入門到實(shí)踐》閱讀筆記 原書地址: https://yeasy.gitbooks.io/docker...
    GuoYuebo閱讀 11,382評(píng)論 1 39
  • 一 去年年底的時(shí)候陆蟆,我開始關(guān)注到認(rèn)知這個(gè)詞語(yǔ)。也是經(jīng)由這個(gè)詞語(yǔ)不斷的反思自己惋增,至今叠殷,我覺得,從這個(gè)詞里收獲良多诈皿! ...
    帝小羽閱讀 2,923評(píng)論 0 15
  • 心情不好的時(shí)候稽亏,看點(diǎn)段子很快就能開懷壶冒。壓力大的時(shí)候,看點(diǎn)段子很快就能放松截歉。無聊的時(shí)候胖腾,看點(diǎn)段子很快就打發(fā)了時(shí)間。 ...
    夏宇嫣_8335閱讀 181評(píng)論 1 2