(开包即用,不用看代码!)借助Windows共享文件夹在Docker中运行Angular

  • 开包即用,不用看代码!
    • 使用管理员权限启动PowerShell
    • 进入工作文件夹
    • 下载代码
    • 进入代码文件夹
    • 更新子模块代码
    • 第1步:共享Windows文件夹到Docker
    • 第2步:测试Docker访问Windows共享文件夹
    • 第3步:启动
    • 第4步:打开浏览器
    • 第5步:使用Visual Studio Code打开Angular应用文件夹
    • 第6步:停止
    • 第7步:清理
  • 补充说明
  • 代码详细分析
    • 第1步:共享Windows文件夹到Docker
    • 第2步:测试Docker访问Windows共享文件夹
    • 第3步:启动
      • Version版本
      • Volume卷
      • 服务node-npm-9.10.0-5.8.0
      • 服务angular.cli-1.7.3
      • 保存镜像
      • 服务ng-new
      • 服务npm-install
      • 服务ng-serve
    • 第4步:打开浏览器
    • 第5步:使用Visual Studio Code打开Angular应用文件夹
    • 第6步:停止
    • 第7步:清理

开包即用,不用看代码!

使用管理员权限启动PowerShell

Windows共享文件夹需要管理员权限

进入工作文件夹

进入你的工作文件夹,例如我的工作文件夹为

Set-Location C:\Users\huzh\OneDrive\Angular

下载代码

git clone https://github.com/huzhenghui/Angular-in-Docker-by-Windows-share-folder.git

进入代码文件夹

Set-Location .\Angular-in-Docker-by-Windows-share-folder

更新子模块代码

git submodule update --init

1步:共享Windows文件夹到Docker

.\step.1.share-windows-folder-to-docker.ps1

输出内容很多,略,结果看下面的测试。

2步:测试Docker访问Windows共享文件夹

.\step.2.share-windows-folder-to-docker.test.ps1

如果从输出结果中看到文件夹的内容,就说明共享设置成功了

Angular-App.vscode.launch.json
LICENSE
angular.cli-1.7.3.Dockerfile
docker-compose.yml
node-npm-9.10.0-5.8.0.Dockerfile
share-windows-folder-to-docker
step.1.share-windows-folder-to-docker.ps1
step.2.share-windows-folder-to-docker.test.ps1
step.3.docker-compose.up.ps1
step.4.open.browser.ps1
step.5.open.code.ps1
step.6.docker-compose.down.ps1
step.7.clean.ps1
......

3步:启动

.\step.3.docker-compose.up.ps1

首次启动的时间比较久,以后就快了,详见本文后面的代码详解。

4步:打开浏览器

运行另一个PowerShell窗口,进入到代码文件夹。

.\step.4.open.browser.ps1

将自动打开浏览器访问该页面。

5步:使用Visual Studio Code打开Angular应用文件夹

在第二个PowerShell窗口中运行。

.\step.5.open.code.ps1

脚本将

  • 自动配置Chrome调试
  • 自动启动Visual Studio Code(需要电脑上安装Visual Studio Code

Visual Studio Code启动后测试自动更新

  1. 按F5快捷键启动调试,
    Visual Studio Code将自动打开Chrome浏览器(需要电脑上安装Chrome浏览器)
  2. 观察自动打开的Chrome浏览器是否自动访问页面
  3. 修改某个程序文件,例如src/app/app.component.ts中的标题名称
  4. 保存
  5. 观察第一个PowerShell窗口是否自动更新
  6. 观察Chrome浏览器是否自动刷新

6步:停止

在第二个PowerShell窗口中运行。

.\step.6.docker-compose.down.ps1

观察第一个PowerShell窗口是否停止服务。

7步:清理

不再使用的时候,可以运行清理脚本

.\step.7.clean.ps1

补充说明

因为步骤较多,第一次建议从第1步到第7步逐步运行一遍,熟悉各步骤。

脚本直接调用dockerdocker-machinedocker-compose等命令,
可能在不同安装方式的电脑上有所不同,如果不能使用请反馈。

7步清理脚本不清理已经设置的共享文件夹,因此清理后再次运行的时候,
可以直接从第3步开始。当然也就不需要使用管理员权限启动PowerShell

3步中首次运行过程较长,很有可能受到网络影响而终止,可以重新运行。
如果重新运行失败,建议使用第7步清理后再次运行。

6步停止后,再次运行第3步将再次启动,再次启动将自动跳过构建的环节。

4步自动通过环境变量获取Docker主机的IP地址,然后使用浏览器访问,
如果不能正确打开请手工试试。

5步自动通过环境变量获取Docker主机的IP地址,
然后生成Visual Studio Code的调试配置文件,本例采用简单粗暴的方式生成,
不同的Visual Studio Code版本可能略有不同,
如果不能正确打开调试请手工配置调试试试。

脚本中把node_modules都扔到了Docker中,
这样的好处是Windows上只包含程序相关代码,坏处就是code找不到这些代码了,
如果需要,可以参照后面的代码说明修改。

代码详细分析

下面详细讲解代码。

1步:共享Windows文件夹到Docker

.\step.1.share-windows-folder-to-docker.ps1

代码如下

.\share-windows-folder-to-docker\share-windows-folder-to-docker.ps1 -volumeName Angular-in-Docker-by-Windows-share-folder -optCache none

这是一个通用的用于共享Windows文件夹到Docker的脚本,参见

https://blog.csdn.net/hu_zhenghui/article/details/79189520

该脚本以gitsubmodule子模块方式引用,因此需要更新子模块代码。

git submodule update --init

脚本中的Windows共享文件夹需要管理员权限,
因此运行这个脚本的PowerShell需要管理员权限。

脚本中操作Docker的部分直接调用dockerdocker-machine命令,
因此需要PowerShell中能直接使用这两个命令。

2步:测试Docker访问Windows共享文件夹

.\step.2.share-windows-folder-to-docker.test.ps1

代码如下

docker run --rm -v Angular-in-Docker-by-Windows-share-folder:/Angular-in-Docker-by-Windows-share-folder alpine ls /Angular-in-Docker-by-Windows-share-folder
docker volume inspect Angular-in-Docker-by-Windows-share-folder

这里的脚本用于测试之前共享Windows文件夹到Docker的脚本。
第一行是在Docker中访问Windows共享的文件夹。
第二行是查看DockerVolume卷的设置。

3步:启动

.\step.3.docker-compose.up.ps1

脚本中的代码很简单

docker-compose up

docker-compose命令将按照docker-compose.yml启动,代码如下:

version: "3.4"
services:
  node-npm-9.10.0-5.8.0:
    image: node-npm:9.10.0-5.8.0
    build:
      context: .
      dockerfile: node-npm-9.10.0-5.8.0.Dockerfile
  angular.cli-1.7.3:
    depends_on:
      - node-npm-9.10.0-5.8.0
    image: angular.cli:1.7.3
    build:
      context: .
      dockerfile: angular.cli-1.7.3.Dockerfile
  ng-new:
    depends_on:
      - angular.cli-1.7.3
    image: angular.cli:1.7.3
    volumes:
      - type: volume
        source: ApplicationRootVolume
        target: /ApplicationRoot
      - type: volume
        source: AngularAppNodeModules
        target: /ApplicationRoot/Angular-App/node_modules
      - Docker-Compose-Startup-Order:/Startup-Order
    command: |
      bash -c '
      echo ng-new start;
      touch /Startup-Order/ng-new.start;
      cd /ApplicationRoot;
      ng new Angular-App;
      echo ng-new done return code = $$?;
      touch /Startup-Order/ng-new.done;'
  npm-install:
    depends_on:
      - ng-new
    image: angular.cli:1.7.3
    volumes:
      - type: volume
        source: ApplicationRootVolume
        target: /ApplicationRoot
      - type: volume
        source: AngularAppNodeModules
        target: /ApplicationRoot/Angular-App/node_modules
      - Docker-Compose-Startup-Order:/Startup-Order
    command: |
      bash -c '
      echo npm-install start;
      touch /Startup-Order/npm-install.start;
      while [[ ! -f /Startup-Order/ng-new.done || /Startup-Order/ng-new.done -ot /Startup-Order/ng-new.start ]]; do sleep 1; done;
      echo npm-install doing;
      cd /ApplicationRoot/Angular-App;
      npm install;
      echo npm-install done;
      touch /Startup-Order/npm-install.done;'
  ng-serve:
    depends_on:
      - npm-install
    image: angular.cli:1.7.3
    volumes:
      - type: volume
        source: ApplicationRootVolume
        target: /ApplicationRoot
      - type: volume
        source: AngularAppNodeModules
        target: /ApplicationRoot/Angular-App/node_modules
      - Docker-Compose-Startup-Order:/Startup-Order
    ports:
      - 80:80
    command: |
      bash -c '
      echo ng-serve start;
      while [[ ! -f /Startup-Order/npm-install.done || /Startup-Order/npm-install.done -ot /Startup-Order/npm-install.start ]]; do sleep 1; done;
      echo ng-serve doing;
      cd /ApplicationRoot/Angular-App;
      ng serve --verbose --progress --host 0.0.0.0 --port 80 --poll 1;'
volumes:
  ApplicationRootVolume:
    external:
      name: Angular-in-Docker-by-Windows-share-folder
  AngularAppNodeModules:
  Docker-Compose-Startup-Order:

下面详细讲解docker-compose.yaml文件。

Version版本

此处使用docker-compose文件的3.4版本,
如果docker-compose不支持这么高的版本可能不能正常运行。

version: "3.4"

Volume

volumes:
  ApplicationRootVolume:
    external:
      name: Angular-in-Docker-by-Windows-share-folder
  AngularAppNodeModules:
  Docker-Compose-Startup-Order:

其中共包含三个卷。

  • ApplicationRootVolume为前面使用脚本共享的Windows文件夹
  • AngularAppNodeModules为内部卷,用于node_modules文件夹,
    也就是把node安装的模块都放在docker中,
    在未来迁移到生产环境的时候,便于隔离项目代码和其他的模块,
    缺点就是后面使用Visual Studio Code打开的时候,找不到这些模块,没有代码提示。
  • Docker-Compose-Startup-Order为内部卷,
    用于控制docker-compose中服务的启动顺序。

服务node-npm-9.10.0-5.8.0

  node-npm-9.10.0-5.8.0:
    image: node-npm:9.10.0-5.8.0
    build:
      context: .
      dockerfile: node-npm-9.10.0-5.8.0.Dockerfile

这个服务的目的就是用于构建node-npm:9.10.0-5.8.0镜像,
构建文件为node-npm-9.10.0-5.8.0.Dockerfile,代码如下

FROM node:9.10.0

LABEL maintainer="[email protected]"

RUN node --version && \
    npm version && \
    npm -g install npm@5.8.0 && \
    npm version

很简单,从node:9.10.0升级[email protected]
这里精确标注版本为了避免经常出现的版本冲突,如果后续遇到版本冲突,
建议按照类似的格式精确构建版本。

本服务的构建过程仅需要运行一次,再次运行不会重复构建镜像。

服务angular.cli-1.7.3

  angular.cli-1.7.3:
    depends_on:
      - node-npm-9.10.0-5.8.0
    image: angular.cli:1.7.3
    build:
      context: .
      dockerfile: angular.cli-1.7.3.Dockerfile

这个服务的目的也是用于构建镜像,镜像为angular.cli:1.7.3
构建文件为angular.cli-1.7.3.Dockerfile,代码如下

FROM node-npm:9.10.0-5.8.0

LABEL maintainer="[email protected]"

RUN npm install -g --unsafe-perm=true @angular/cli@1.7.3 && \
    ng version

注意这里使用服务node-npm-9.10.0-5.8.0构建的node-npm:9.10.0-5.8.0镜像,
为了控制构建顺序,需要设置依赖关系。

    depends_on:
      - node-npm-9.10.0-5.8.0

构建内容就是安装@angular/[email protected],然后显示版本ng version

本服务的构建过程仅需要运行一次,再次运行不会重复构建镜像。

保存镜像

由于构建镜像不稳定,建议在构建镜像后保存镜像,因为都是开源软件,
所以可以保存在docker的公共镜像库中,在 http://hub.docker.com/ 上注册账号。

在本地登录

docker login

在 http://hub.docker.com/ 上创建镜像仓库,我创建的镜像仓库为

  • huzhenghui/node-npm
  • huzhenghui/angular.cli

在本地按照镜像仓库的名称给镜像打标签。

docker tag node-npm:9.10.0-5.8.0 huzhenghui/node-npm:9.10.0-5.8.0
docker tag angular.cli:1.7.3 huzhenghui/angular.cli:1.7.3

然后上传镜像。

docker push huzhenghui/node-npm:9.10.0-5.8.0
docker push huzhenghui/angular.cli:1.7.3

上传后即可在 http://hub.docker.com/ 上看到。

https://hub.docker.com/r/huzhenghui/node-npm/
https://hub.docker.com/r/huzhenghui/angular.cli/

未来使用的时候,可以拉取镜像,拉取镜像不需要登录。

docker pull huzhenghui/node-npm:9.10.0-5.8.0
docker pull huzhenghui/angular.cli:1.7.3

然后测试镜像

docker run -it --rm huzhenghui/angular.cli:1.7.3 ng -v
docker run -it --rm huzhenghui/angular.cli:1.7.3 bash

为了和docker-compose.yml中的镜像名称保持一致,给镜像打标签。

docker tag huzhenghui/node-npm:9.10.0-5.8.0 node-npm:9.10.0-5.8.0
docker tag huzhenghui/angular.cli:1.7.3 angular.cli:1.7.3

服务ng-new

  ng-new:
    depends_on:
      - angular.cli-1.7.3
    image: angular.cli:1.7.3
    volumes:
      - type: volume
        source: ApplicationRootVolume
        target: /ApplicationRoot
      - type: volume
        source: AngularAppNodeModules
        target: /ApplicationRoot/Angular-App/node_modules
      - Docker-Compose-Startup-Order:/Startup-Order
    command: |
      bash -c '
      echo ng-new start;
      touch /Startup-Order/ng-new.start;
      cd /ApplicationRoot;
      ng new Angular-App;
      echo ng-new done return code = $$?;
      touch /Startup-Order/ng-new.done;'

这个服务用于新建angular项目,使用前面构建的angular.cli:1.7.3
因此设置依赖关系。

    depends_on:
      - angular.cli-1.7.3

挂载了三个卷,其中

  • ApplicationRootVolume是从Windows共享的文件夹,挂载在/ApplicationRoot
  • AngularAppNodeModules是内部卷,
    挂载在/ApplicationRoot/Angular-App/node_modules
    注意挂载位置在ApplicationRootVolume挂载位置的内部,
    这是docker的强大功能之一,可以灵活的控制文件写入的位置。
  • Docker-Compose-Startup-Order是内部卷,挂载在/Startup-Order

服务的命令直接写脚本,头尾用于控制服务的运行顺序。

touch /Startup-Order/ng-new.start;
touch /Startup-Order/ng-new.done;

中间部分这是新建angular项目。

cd /ApplicationRoot;
ng new Angular-App;

仅在首次运行的时候有较长的运行时间,
再次运行的时候检测到已经创建了项目就会自动结束。

服务npm-install

  npm-install:
    depends_on:
      - ng-new
    image: angular.cli:1.7.3
    volumes:
      - type: volume
        source: ApplicationRootVolume
        target: /ApplicationRoot
      - type: volume
        source: AngularAppNodeModules
        target: /ApplicationRoot/Angular-App/node_modules
      - Docker-Compose-Startup-Order:/Startup-Order
    command: |
      bash -c '
      echo npm-install start;
      touch /Startup-Order/npm-install.start;
      while [[ ! -f /Startup-Order/ng-new.done || /Startup-Order/ng-new.done -ot /Startup-Order/ng-new.start ]]; do sleep 1; done;
      echo npm-install doing;
      cd /ApplicationRoot/Angular-App;
      npm install;
      echo npm-install done;
      touch /Startup-Order/npm-install.done;'

代码结构和服务ng-new类似,命令的头尾也是用于控制服务的运行顺序。

touch /Startup-Order/npm-install.start;
while [[ ! -f /Startup-Order/ng-new.done || /Startup-Order/ng-new.done -ot /Startup-Order/ng-new.start ]]; do sleep 1; done;
touch /Startup-Order/npm-install.done;'

其中的while循环就是检测服务ng-new是否运行结束,对照服务ng-new即可理解。

中间部分是安装node包。

cd /ApplicationRoot/Angular-App;
npm install;

仅在首次运行的时候有较长的运行时间,
再次运行的时候检测到已经安装了包就会自动结束。

服务ng-serve

  ng-serve:
    depends_on:
      - npm-install
    image: angular.cli:1.7.3
    volumes:
      - type: volume
        source: ApplicationRootVolume
        target: /ApplicationRoot
      - type: volume
        source: AngularAppNodeModules
        target: /ApplicationRoot/Angular-App/node_modules
      - Docker-Compose-Startup-Order:/Startup-Order
    ports:
      - 80:80
    command: |
      bash -c '
      echo ng-serve start;
      while [[ ! -f /Startup-Order/npm-install.done || /Startup-Order/npm-install.done -ot /Startup-Order/npm-install.start ]]; do sleep 1; done;
      echo ng-serve doing;
      cd /ApplicationRoot/Angular-App;
      ng serve --verbose --progress --host 0.0.0.0 --port 80 --poll 1;'

代码结构和服务ng-new类似,
区别在于服务ng-serve提供web服务,因此需要打开80端口。

    ports:
      - 80:80

命令头部的while循环就是检测服务npm-install是否运行结束,
对照服务npm-install即可理解。

while [[ ! -f /Startup-Order/npm-install.done || /Startup-Order/npm-install.done -ot /Startup-Order/npm-install.start ]]; do sleep 1; done;

然后启动web服务。

ng serve --verbose --progress --host 0.0.0.0 --port 80 --poll 1;

其中--host 0.0.0.0为绑定全部地址,默认仅绑定localhost
docker中运行时外部是访问不到的。
--port 80为绑定80端口,默认绑定4200端口。
--poll 1用于加快检查文件是否有更新,后面Visual Studio Code环节会详细讲解。

4步:打开浏览器

因为第一个PowerShell窗口中正在显示ng-serve服务,
因此需要运行另一个PowerShell窗口,进入到代码文件夹。

.\step.4.open.browser.ps1

代码如下。

if ($env:DOCKER_HOST -match "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b")
{
    Start-Process (-Join('http://', $Matches[0], '/'))
}

其中$env:DOCKER_HOSTdocker的环境变量,使用如下代码查看。

Write-Output $env:DOCKER_HOST

输出结果类似为

tcp://192.168.1.101:2376

脚本从这个环境变量中解析出IP地址,本例中即为192.168.1.101
然后拼接成网址,本例中即为http://192.168.1.101/
再打开浏览器访问,Windows下默认为Edge浏览器。

打开浏览器后应能看到angular项目的初始界面,
如果看不到请按照按照前面的讲解排查。

5步:使用Visual Studio Code打开Angular应用文件夹

继续在第二个PowerShell窗口中运行。

.\step.5.open.code.ps1

内容如下。

if ($env:DOCKER_HOST -match "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b")
{
    if(!(Test-Path .\Angular-App\.vscode))
    {
        New-Item -ItemType "directory" .\Angular-App\.vscode\
    }
    if(!(Test-Path .\Angular-App\.vscode\launch.json))
    {
        $launch=Get-Content -Encoding UTF8 .\Angular-App.vscode.launch.json | ConvertFrom-Json
        $launch.configurations[0].name=-Join("Launch Chrome and Open ", $Matches[0])
        $launch.configurations[0].url=-Join('http://', $Matches[0], '/')
        $launch | ConvertTo-Json | Out-File -Encoding UTF8 .\Angular-App\.vscode\launch.json
    }
}
code .\Angular-App\

脚本的第一部分是自动配置Chrome调试,和前面类似,也是先解析出IP地址。

如果没有.\Angular-App\.vscode文件夹则创建该文件夹。

如果没有.\Angular-App\.vscode\launch.json则从模板创建。创建方式简单粗暴,
直接使用默认生成的launch.json文件创建,
因此如果遇到Visual Studio Code版本升级导致不兼容,
请参照这里介绍的工作原理调试。
读取模板后,修改name名称,和url地址,然后保存到目标位置。

脚本的第二部分自动启动Visual Studio Code,当然需要电脑上安装Visual Studio Code

Visual Studio Code启动后可以测试自动更新。

  1. 按F5快捷键启动调试,
    Visual Studio Code将自动打开Chrome浏览器(需要电脑上安装Chrome浏览器)
  2. 观察自动打开的Chrome浏览器是否自动访问页面
  3. 修改某个程序文件,例如src/app/app.component.ts中的标题名称
  4. 保存
  5. 观察第一个PowerShell窗口是否自动更新
  6. 观察Chrome浏览器是否自动刷新

6步:停止

继续在第二个PowerShell窗口中运行。

.\step.6.docker-compose.down.ps1

代码很简单。

docker-compose down

观察第一个PowerShell窗口是否停止服务。
需要注意停止服务时需要在启动服务相同的文件夹。

7步:清理

不再使用的时候,可以运行清理脚本

.\step.7.clean.ps1

代码如下。

Remove-Item -Recurse -Force .\Angular-App\* -Confirm
Remove-Item .\Angular-App\
docker volume rm angularindockerbywindowssharefolder_AngularAppNodeModules
docker volume rm angularindockerbywindowssharefolder_Docker-Compose-Startup-Order

删除新建的angular项目,删除docker中相关的卷。

你可能感兴趣的:(Docker,Angular,Chrome,Visual,Studio,Code,Node)