分享一个在云主机上的无桌面环境Windows Server上,不安装Docker Desktop,运行Docker

系统要求Windows2016及以上即可。

起因

前段时间,一朋友委托我研究一个技术方案。说他技术这边搞了一个分布式的Windows程序,依赖Docker环境,现在只能在电脑上安装,非常不方便维护,扩容起来也很麻烦。于是我也花了差不多花了一百多块钱,一个周末,买了一个云主机来研究研究。

太长不看

利用DOCKER_HOST参数将windows的docker客户端通过tcp方式连接到wsl内的dockerd服务

参数字段daemon-socket-option

说起来是很简单,第一次操作起来还是遇到了很多问题。

研究

现在因为已经知道结论了,所有写起来理所当然,实际上花了大把时间才得到这个结局。众所周知,Windows云主机有几个遇到的问题:

Windows Server版本问题

WindowsServer版本信息

Windows Server也开始走LTS方式来迭代,但是名字和版本真的混乱,可以说是一塌糊涂。我也是搞了很久才理清楚。只有LTS版是有名字的,比如Windows2016、Windows2019、Windows2022。其他非LTS是没名字的,直接用版本号指代,版本号其实就是发布日期,比如1803、1809、1909、2004,到后面也不用月份了直接20H2,21H2,因为一年只发布两次。三年一个大发布,就是LTS。所以Windows2019目前就是版本1809。下一次LTS是Windows2022,版本是21H2。

遇到一个最大的问题是,非LTS版是默认是没有桌面环境的。虽然今年就是2022年了,Windows2022也能下载了,但是云服务商还没有这么快的速度有这个系统版本。国内看了一圈最新提供的还是2004。于是意味着,我们要么使用1809这个老版本,要么使用稍微新一点点的无UI环境的2004。

然后我发现,DockerDesktop必须要有UI才能安装,

搞了很久,其实到最后才发现,版本其实不重要。因为在第二个遇到的问题面前,版本都是虚的。

虚拟化问题

我们平常使用Linux的,使用docker的时候完全不用考虑虚拟化问题,docker都是开箱即用。但是Windows就复杂了一些。整理了半天发现绕不开这个问题。一旦遇到这个问题,会发现前面的努力都白费了。云服务器几乎不能二次虚拟化的,因为云服务器本身就是虚拟化出来的。当然也不是没有,有一些虚拟化技术是可以实现的,加钱肯定可以解决就是了。

开始解决

之前也查了很多资料,发现居然没有一个解决办法。

目前常规的做法,包括官方都是安装WSL2,安装Docker Desktop。后来看docker文档,想到一个参数,daemon-socket-option。当时还在想,难道要再买一台服务器安装Ubuntu,Windows这边再连接过来吗。后来脑子一转,没有wsl2,咱们还有wsl1啊,这个是不需要虚拟化就可以安装的啊! 于是开始操作。

说起来是很简单,第一次操作起来还是遇到了很多问题。而且为了后续能批量扩容,只保留了最小的操作。

远程连接到服务器上之后发现只有一个CMD窗口

但是实际上大部分操作都是在powershell中操作的

1. 安装Ubuntu2004与docker客户端

官方文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 启用WSL
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux

# 重启
Restart-Computer -Force

# Ubuntu2018
Invoke-WebRequest -Uri "https://aka.ms/wsl-ubuntu-1804" -OutFile "wslubuntu2018.appx"

# 解压然后安装
Rename-Item .\wslubuntu2018.appx .\wslubuntu2018.zip
Expand-Archive .\wslubuntu2018.zip .\Ubuntu
cd .\Ubuntu
.\ubuntu1804.exe

# ubunut2004也可以,安装包大很多,格式不一样,安装方式不一样,需要再查一下
# Invoke-WebRequest -Uri "https://aka.ms/wslubuntu2004" -OutFile "wslubuntu2004.AppxBundle"

发现安装好Ubuntu之后,bash对终端的样式都改变了

1
2
3
# 安装docker客户端
Install-Module -Name DockerMsftProvider -Repository PSGallery -Force
Install-Package -Name docker -ProviderName DockerMsftProvider

安装完成之后执行命令可以发现没有启动服务,然后再重启一次。

重启之后到powershell里运行docker命令,发现是可以运行的。也有了服务,这是怎么回事呢。后来我又去查了一波。

windows下有一个自己的容器服务。如果是平时用docker desktop的同学在右键的时候应该可以发现会有一个Windows Container。相当于是基于window内核的一个容器服务。但是它只能运行基于windows的镜像。比如平时我们运行的各种甚至是hello-world都运行不了,报错操作系统不兼容。

如果嫌多余可以关闭服务

1
net stop docker

2. 安装wsl里的docker服务端

安装好Ubuntu之后,在powershell里直接运行bash可以进入子系统,就和平时的一样操作就可以了。

最好先更新系统apt dist-upgrade
一个坑,不能安装最新版,我安装了17.12
记得增加docker组
cgroup可能有问题,手动安装一下

安装了之后,运行了运行helloworld,完全没问题。

1
2
3
4
5
6
# 启动服务
sudo dockerd


# 运行测试
docker run hello-world

3. 设置指定端口启动

1
2
3
4
5
6
# 启动服务
sudo dockerd -H tcp://0.0.0.0:8888


# 运行测试, 可以在ubuntu里运行,也可以在windows里运行
docker -H tcp://0.0.0.0:8888 run hello-world

如果不想每次使用-H参数,可以设置环境变量

1
[System.Environment]::SetEnvironmentVariable("DOCKER_HOST", "tcp://127.0.0.1:8888")

这样就默认使用wsl里的docker服务

结语

总的来说还是有不少收获,特别是关于windows server的东西。平时用的最多的还是ubuntu或者centos,几乎不接触windows server,即使少有的也都是带桌面环境的。安装软件程序点点点就可以,和日常桌面使用一样。也是没有想到windows server居然还有包管理,就是上面的powershell相关的命令。

唯一的一个问题是,挂载目录用当前的方式还是有一点点问题,不能直接传入windows的路径格式。而普通方式的是可以直接挂载windows路径的,比如C:\User\这样的,不会把冒号作为命令分隔。

于是从挂载这个问题上继续思考,其实也写一个bash脚本,名字叫docker,加到环境变量里。windows这边直接调用这个docker实际是执行这个bash,也就是会把脚本传入wsl里执行。然后在这脚本里可以做路径相关的替换。貌似这也是一种方案。后续可以试试看。