背景#

我校的操作系统课程设计是斯坦福大学的 pintos 项目(当然只需要完成少量的 project)。pintos 需要在 x86 架构的 Linux 系统上运行,但是我最近主力使用的是一台 Macbook Pro,我不太愿意每天背着两台电脑去图书馆。

我原本的设想是把我运行 Ubuntu 机器放在宿舍,通过校园网 ssh 连接到它。但是这样做有两个问题:

  1. 校园网的网络环境不太好,即使是使用代理也无法保证一些软件源的稳定连接。
  2. 学校最近在进行消防安全检查,不允许离开宿舍时不断电源,而我没法保证宿舍时刻都有人。

看起来,我只能在 Mac 上跑一个虚拟机了;然而我不太喜欢使用虚拟机的使用体验:在运行时占用太多的内存,启动或者关闭需要等待太长的时间。我希望有一个更轻量的解决方案。

最近,我关注的 up 主 @TheCW 在沉寂了一年之后忽然更新了一个视频。我重新回看了他之前发布的几个视频后,忽然发现他在 Mac 上需要一个 Linux 环境时,直接用 docker run 了一个全新的 Ubuntu 镜像,这个方法看起来非常轻巧——非常适合我。

下文是我在 Mac 上使用 docker 运行 Ubuntu 的步骤。

安装 Docker Desktop for Mac#

访问 Docker 官网 下载 Docker Desktop for Mac 即可,这部分不再赘述。

下载并运行 Ubuntu 镜像#

在终端中输入以下命令来拉取 Ubuntu 镜像:

docker pull --platform linux/amd64 ubuntu

我使用 –platform 来指定镜像的架构,因为我需要一个 x86 架构的镜像;如果直接使用 docker pull ubuntu,docker 会默认自动选择当前机器的架构,这对我来说当然是不行的。

拉取完成后,运行以下命令来启动一个新的 Ubuntu 容器:

docker run --platform linux/amd64 -it ubuntu /bin/bash

这个命令会启动一个新的 Ubuntu 容器,并且进入 bash shell。不过,这个容器还是一个全新的、仅包含最基本软件的 Ubuntu 系统,它看起来应该是这样的:

wood@Woods-MacBook-Pro ~> docker exec -it ubuntu bash
root@8d907eeb-----:/# 

如果需要退出容器,使用 exit 命令。

如果要重新进入容器,可以使用 docker ps -a 查看容器的 ID,然后使用 docker start <container-id>docker attach <container-id> 命令。

我们首先应该要新建一个用户,因为 root 用户不应该用于日常操作。在容器中依次以下命令:

apt update
apt install sudo adduser
adduser <your-username>

如果你在 apt update 时遇到了网络问题,可以尝试更换软件源,或者使用代理(参看代理 Docker 容器)。

在按照提示设置密码和其他信息后,我们需要将新建的用户加入 sudo 组:

usermod -aG sudo <your-username>

使用 su 命令切换到新建的用户,并测试一下 sudo 是否正常工作:

su - <your-username>
sudo whoami

如果输出为 root,则说明 sudo 已经正常工作。

Docker 快捷命令#

在继续配置 Ubuntu 容器之前,我想先让启动和退出容器更加方便。

首先使用 docker ps -a 查看容器的 ID,然后使用 docker rename <container-id> ubuntu 命令为容器设置别名为 ubuntu。

随后,我在 ~/.config/fish/config.fish 中添加了以下两个 alias:

alias ubuntu 'docker start ubuntu && docker attach ubuntu'
alias ubuntu-stop 'docker stop ubuntu'

运行 source ~/.config/fish/config.fish 使配置生效。

ps: 如果你使用的是 bash,可以将 alias 添加到 ~/.bashrc 中,并运行 source ~/.bashrc,注意,bash 的 alias 语法和 fish 有所不同,需要使用一个 = 号:alias ubuntu='docker start ubuntu && docker attach ubuntu'

配置 Ubuntu 容器#

fish shell#

我习惯使用 fish shell,并以 fish 为默认 shell。在容器中,我首先安装了 fish shell:

sudo apt install fish

我没有使用 chsh 命令来更改默认 shell,而是直接修改了对 ubuntu 命令的 alias:

alias ubuntu "docker start ubuntu && \
docker exec -it --user <your-username> \
ubuntu fish -C 'cd ~'"

这样,每次进入容器时,都会以普通用户的身份进入 fish shell,并且进入到用户目录。

到这里,我已经接近了日常使用 Ubuntu 的体验。

screenfetch#

我喜欢登陆时看到 screenfetch,诚实地说,是因为这满足了我小时候对“黑客”的幻想。

我需要在 Docker 容器中安装 screenfetch,然后在 fish 的配置文件中添加 screenfetch 命令。

sudo apt install screenfetch
echo "screenfetch 2>/dev/null" >> ~/.config/fish/config.fish

这里,因为 screenfetch 无法访问宿主机的信息,会显示一行错误信息,所以我在 screenfetch 命令后面加了一个 2>/dev/null 来丢弃错误信息。

我说,谁能拒绝一个 screenfetch 呢?

screenfetch

配置 Docker 容器代理#

注意,这不是代理 Docker 的软件源,而是代理 Docker 容器内的网络。

编辑 ~/.docker/config.json 文件,添加以下内容:

{
  "proxies": {
    "default": {
     "httpProxy": "http://proxy.example.com:8080",
     "httpsProxy": "http://proxy.example.com:8080"
    }
  }
}

这里的 httpProxyhttpsProxy 需要根据你实际的代理设置进行修改。