Docker实践:使用Docker搭建个人开发环境

文章目录

  • 环境配置
    • 必备环境
      • 主机
    • 推荐环境
      • 主机
      • 容器
  • 软件一
    • 安装
    • 配置
      • 终端&脚本
      • Chrome浏览器
      • 应用商店
      • Docker
        • Docker Daemon
        • 针对build命令
        • 针对pull命令
        • 针对run命令
        • 针对容器
  • 软件二
    • 安装
    • 配置
  • 含Nvidia独显开发环境搭建教程
    • 1. 编写docker-compose.yml
    • 2. 设置显卡
    • 3. 在容器内配置开发环境
    • 4. 保存/备份容器
    • 5. 修改docker-compose.yml
    • 6. 开始使用
  • 无Nvidia独显开发环境搭建教程
    • 1. 编写Dockerfile并构建镜像
    • 2. 编写docker-compose.yml
    • 3. 在容器内配置开发环境
    • 4. 保存/备份容器
    • 5. 修改docker-compose.yml
    • 6. 开始使用
  • 常见问题与解答
    • 在容器内使用git clone的时候报错,显示Bad owner or permissions on /root/.ssh/config
    • 容器和主机间能共享文件,但是打不开/不能编辑/无法执行
    • 无法运行GUI程序
    • 容器内环境崩了,如何恢复
    • 在容器内能不能使用主机的用户

使用Docker搭建开发环境:

  • 可以避免因配环境失误导致系统崩溃,更换电脑或重装系统后也可快速恢复工作环境,相当于备份系统
  • 只需下载镜像启动容器即可使用,方便部署在其他设备上,既统一了环境,便于查找问题,又节约了配环境的时间
  • 想使用不同的系统及相应的软件,不需要重装系统,新建一个镜像,在镜像内搭建环境就能使用
  • Docker Hub、GitHub上有很多开源的Dockerfile和已经制作好的镜像,在它们的基础上定制自己的环境也很方便,不需要从0开始搭建
  • 跨平台,例如x86平台上构建好用于arm平台的镜像,可以在x86上运行、测试好后部署到arm平台
  • 在Windows上也能使用Linux系统,且比虚拟机节约资源
  • 方便导入和导出,一个压缩包就能打包环境

环境配置

必备环境

主机

  • Ubuntu
    我使用的是Kubuntu 22.04,基于Ubuntu 22.04 的一个风味发行版,功能非常丰富,详情见官网
    Ubuntu18.04、Ubuntu20.04、Ubuntu22.04等版本也可正常使用
  • Nvidia驱动
    若要在容器内使用Nvidia显卡,需要在主机中安装nvidia显卡驱动(建议安装最新版本,使用系统自带的驱动管理程序安装)并安装 NVIDIA Container Runtime,安装教程见Ubuntu下 NVIDIA Container Runtime 安装与使用
nvidia-smi

Tue Aug  9 11:13:42 2022       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 515.65.01    Driver Version: 515.65.01    CUDA Version: 11.7     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA GeForce ...  Off  | 00000000:01:00.0  On |                  N/A |
| N/A   47C    P5    25W /  N/A |    570MiB /  8192MiB |     22%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|    0   N/A  N/A      1238      G   /usr/lib/xorg/Xorg                286MiB |
|    0   N/A  N/A      2020      G   /usr/bin/kwin_x11                 115MiB |
|    0   N/A  N/A      2074      G   /usr/bin/plasmashell               99MiB |
|    0   N/A  N/A      6161      G   ...159984077981301337,131072       63MiB |
+-----------------------------------------------------------------------------+

  • docker版本
    不要使用Docker Desktop for Linux(若想通过GUI程序管理Docker,可使用Portainer CE等其他开源工具)。经测试,可能会出现无法显示容器内GUI程序的问题,安装教程见Docker官方文档学习笔记(一):安装、升级、卸载Docker,有耐心的可以看一下Docker专栏里的Docker官方文档学习笔记,官方文档用的是Docker Desktop for Linux,但使用Docker Engine同样可以走完教程,讲Docker Desktop for Linux操作的部分跳过就可以了
docker version                                                              

Client: Docker Engine - Community
 Version:           20.10.17
 API version:       1.41
 Go version:        go1.17.11
 Git commit:        100c701
 Built:             Mon Jun  6 23:02:46 2022
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.17
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.17.11
  Git commit:       a89b842
  Built:            Mon Jun  6 23:00:51 2022
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.6
  GitCommit:        10c12954828e7c7c9b6e0ea9b0c02b01407d3ae1
 runc:
  Version:          1.1.2
  GitCommit:        v1.1.2-0-ga916309
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
  • vscode
    安装扩展并登陆帐号以便同步扩展和设置,必备扩展为微软的Remote
    Docker实践:使用Docker搭建个人开发环境_第1张图片

推荐环境

主机

  • 主机安装日常所需的软件即可,例如WPS、百度网盘、Chrome、cmake、git等
  • zsh及其相关插件,安装教程见ZSH、oh-my-zsh安装教程及插件和主题推荐
  • 开热点的linux-wifi-hotspot
  • 代理,教程见Ubuntu安装v2ray的QT客户端、Electron,配置全局&PAC代理,终端&脚本、Chrome浏览器、应用商店、Docker均可使用,本文也会展示该博文内容,见目录中的“软件一”、“软件二”
    推荐两个软件,都是从snap商店下载(就是系统自带的软件商店Ubuntu Software),软件名称如图所示,在商店直接按名称搜索即可安装,为方便区分,下文以软件一(左)、软件二(右)代替这两个软件的名称
    Docker实践:使用Docker搭建个人开发环境_第2张图片
  • vscode扩展,这里以截图的形式展示
    Docker实践:使用Docker搭建个人开发环境_第3张图片
    Docker实践:使用Docker搭建个人开发环境_第4张图片
    Docker实践:使用Docker搭建个人开发环境_第5张图片
    Docker实践:使用Docker搭建个人开发环境_第6张图片

容器

同样是zsh及其相关插件,安装教程见ZSH、oh-my-zsh安装教程及插件和主题推荐

软件一

安装

  1. 打开软件商店,输入软件名称,然后点击Install下载安装(若下载速度过慢,尝试本文中的方法一)
    可能会出现下载一会失败的情况,使用以下命令解决
    sudo snap changes #查看ID
    
    sudo snap abort [ID] #将 [ID] 替换为实际安装qv2ray的ID,例如 sudo snap abort 49
    

Docker实践:使用Docker搭建个人开发环境_第7张图片

  1. 下载核心文件(链接见表格,整行复制粘贴到浏览器地址栏,删掉其中多余的空格和制表符),选择linux-64版本下载,等软件一下载好后,解压到如图所示的文件夹(.config是隐藏文件夹,需要在文件管理器的设置中勾选“显示隐藏文件(show hidden files)才会显示”)
    Docker实践:使用Docker搭建个人开发环境_第8张图片
https://github.com/v2 fly/v2 ray-core/releases
  1. 下载链接解析插件(链接见表格,整行复制粘贴到浏览器地址栏,删掉其中多余的空格和制表符),下v2.0.3.linux-x64.so就可以,因为软件商店下载的软件一是v2.6.0版本,更高版本的链接解析插件不支持该版本
https://github.com/Qv2 ray/QvPlugin-SS R/releases/tag/v2.0.3
  1. 第一次打开软件一,会提示有2.7.0版本,不升级,点击忽略。打开左上角首选项
    Docker实践:使用Docker搭建个人开发环境_第9张图片
    内核设置中点击“检查核心设置”,若已按照步骤2.解压并移动到指定位置,则会有以下提示
    Docker实践:使用Docker搭建个人开发环境_第10张图片
    入站设置中将监听地址改为“0.0.0.0”
    Docker实践:使用Docker搭建个人开发环境_第11张图片
    连接设置如图所示
    Docker实践:使用Docker搭建个人开发环境_第12张图片
    最后点右下角的“OK”完成设置

  2. 在软件首页点击插件,“打开本地插件目录”
    Docker实践:使用Docker搭建个人开发环境_第13张图片
    把步骤3.中下载好的插件放到该目录,然后重启程序,再次打开插件,若显示如上图所示,则说明安装成功
    Docker实践:使用Docker搭建个人开发环境_第14张图片

  3. 点击程序首页下方的分组,再点击“组列表”下方垃圾桶图标左边的图标,添加一个分组,在“订阅设置”中勾选“此分组是一个订阅”,输入订阅地址,点击下方“更新订阅”中,然后点ok完成设置
    Docker实践:使用Docker搭建个人开发环境_第15张图片

  4. 回到程序首页,就可以在分组中选择服务器使用了

配置

终端&脚本

使用的如果是bash,则修改~/.bashrc,添加如下两行,zsh同理修改~/.zshrc

export http_proxy="http://127.0.0.1:8889"
export https_proxy="http://127.0.0.1:8889"

若是脚本,则在脚本开头加入这两行即可

若apt安装还是速度慢,见Ubuntu设置apt代理(使用Synaptic Package Manager 新立得软件包管理器、修改 /etc/apt/apt.conf.d/proxy.conf 文件、修改 .bashrc)

Chrome浏览器

Chrome使用的是系统的代理设置,所以需要修改系统代理
该图为Ubuntu的设置
Docker实践:使用Docker搭建个人开发环境_第16张图片
该图为Kubuntu的设置
Docker实践:使用Docker搭建个人开发环境_第17张图片

应用商店

见Ubuntu Snap商店代理设置方法的方法二

Docker

对于不同的使用情景,需要在不同地方设置,建议一次全设置上,若没有安装Docker Desktop for Linux,则不需要针对run命令使用方法三

Docker Daemon
  1. 为docker服务创建systemd目录
sudo mkdir -p /etc/systemd/system/docker.service.d
  1. 创建一个名为 /etc/systemd/system/docker.service.d/http-proxy.conf 的文件并添加一个或多个环境变量
sudo vim /etc/systemd/system/docker.service.d/http-proxy.conf

以下为示例内容

[Service]
Environment="HTTP_PROXY=http://127.0.0.1:8889"
Environment="HTTPS_PROXY=http://127.0.0.1:8889"
Environment="NO_PROXY=localhost,127.0.0.1"
  1. 刷新更改并重新启动Docker
sudo systemctl daemon-reload
sudo systemctl restart docker
  1. 验证是否加载成功
sudo systemctl show --property=Environment docker
针对build命令

方法一

针对pull命令

为docker pull设置代理

针对run命令

方法三

针对容器

方法二

软件二

安装

  1. 直接在Ubuntu Software搜索并安装,或使用命令
    在这里插入图片描述

Docker实践:使用Docker搭建个人开发环境_第18张图片

  1. 应用程序菜单找到程序,打开后点击左下角“+”添加配置
    Docker实践:使用Docker搭建个人开发环境_第19张图片
  2. 右下角分别有三个选项,其中手动相当于关闭,根据需求三选一即可
    Docker实践:使用Docker搭建个人开发环境_第20张图片

使用Electron的好处是不需要再去Ubuntu的设置里面手动修改地址和端口,选择任意一项,软件都会自动修改Ubuntu的配置,弊端是不像软件一可以修改监听地址,使用软件二无法设置docker build命令的代理,因为docker build的代理地址是本机的局域网ip地址,监听地址不改为0.0.0.0,无法通过局域网代理

配置

参照软件一的配置教程即可,凡是代理地址为127.0.0.1的设置都能生效
若想局域网共享代理,则须使用软件一,将监听地址设置为0.0.0.0,然后其他设备中代理地址填写本机的ip和开放的端口即可(本教程中为8889端口)

含Nvidia独显开发环境搭建教程

适用于有Nvidia独显的主机并希望能在容器中使用独显

需要在主机中安装nvidia显卡驱动(建议安装最新版本,使用系统自带的驱动管理程序安装)并安装 NVIDIA Container Runtime,安装教程见Ubuntu下 NVIDIA Container Runtime 安装与使用

1. 编写docker-compose.yml

之前尝试过写Dockerfile,然后手动安装cuda和cudnn,很麻烦,因此直接使用nvidia的cuda镜像,在它的基础上定制自己的镜像

使用 docker run 运行容器的时候,需要加很多参数,相比之下docker-compose.yml简化了run后跟的参数,将运行时的参数全部写到yml文件里面,只需执行 docker compose up -d 就可以启动,达到和 docker run 一样的效果

docker-compose.yml原本是为一次管理多个容器而设计的(见Docker官方文档学习笔记(二):入门),在这里管理一个容器同样方便

# 这个version指的是compose文档的官方版本,不同版本号所含的功能不同
# 具体见 https://docs.docker.com/compose/compose-file/compose-versioning/
# 编写本教程时的最新版本为3.8
version: '3.8'
# 项目名称
name: my_dev
# 所有的容器的定义都要在services这个顶级元素下定义
services:
  # 服务名称,可以与项目名称保持一致
  my_dev:
    # 设置为true,则容器内PID为1的进程就会是docker提供的一个init程序
    # 这样可以使容器能够回收内部的僵尸进程,避免占用资源
    init: true
    # 容器名称,可以与服务名称保持一致
    container_name: my_dev
    # 网络模式设置为host,就可以与主机使用同一个网络,而不是使用docker虚拟网卡的桥接网络,方便设置代理和ssh连接
    network_mode: "host"
    # 设置为true,则容器内的root用户与主机的root用户具有相同的权限
    privileged: true
    # 使用nvidia官方镜像:cuda11.6.2,cudnn8,ubuntu18.04
    # 更多镜像见 https://hub.docker.com/r/nvidia/cuda/tags?page=1&ordering=last_updated
    image: nvidia/cuda:11.6.2-cudnn8-devel-ubuntu18.04
    # 设置容器启动后自动执行的命令,不能为空
    # 容器内PID为1的进程退出后,容器就会关闭,为了防止容器自动关闭,就需要让容器一直运行程序
    # 这个命令可以防止容器启动后自动退出
    command: tail -f /dev/null
    # 设置要挂载的目录,可以理解为共享文件夹
    volumes:
      # 使容器和主机共用一套ssh密钥,但主机内该文件夹的config文件(如果存在的话)不能被容器内的root用户使用,
      # 可能会报错(Bad owner or permissions on /root/.ssh/config)。
      # 这个config文件是vscode保存ssh连接的,权限为600
      # 解决办法是将主机的这个config文件改名,例如改为config.back
      # 但推荐方法是重新设置vscode保存ssh连接的文件的路径,下文会介绍
      # - "~/.ssh:/root/.ssh:rw" # 本来是为了省事,现在不推荐挂载,因为会导致一些报错,处理起来比较麻烦。
      # 显示GUI所必须的
      - "/tmp/.X11-unix:/tmp/.X11-unix:rw"
      # 使容器可以读取到外接设备
      # 比如主机上插了一个USB相机,挂载/dev后,容器内就也可以使用该相机了
      - "/dev:/dev:rw"
      # 将docker-compose.yml所在目录下的ENVIRONMENTS文件夹(如果不存在则会自动创建一个)共享到容器中
      # 目的是方便在容器和主机间共享数据
      - "./ENVIRONMENTS:/root/ENVIRONMENTS:rw"
      # 将docker-compose.yml所在目录下的SHARE文件夹(如果不存在则会自动创建一个)共享到容器中
      # 目的是方便在容器和主机间共享数据
      - "./SHARE:/root/SHARE:rw"
      # 与主机共用git配置
      # - "~/.gitconfig:/root/.gitconfig:rw" # 这个也就不推荐挂载了
    # 设置容器的默认工作目录
    working_dir: /root
    # 设置环境变量
    environment:
      # 显示GUI所必须的
      - DISPLAY=$DISPLAY
      - QT_X11_NO_MITSHM=1
      # 将语言设置成简体中文
      - LC_ALL=zh_CN.UTF-8
      # 启用GPU驱动的所有功能
      - NVIDIA_DRIVER_CAPABILITIES=all
    # 启用GPU
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]

关于GPU的更多配置,见Ubuntu下 NVIDIA Container Runtime 安装与使用

2. 设置显卡

在主机的nvidia显卡设置中(即nvidia-settings),找到PRIME Profiles,选择NVIDIA(Performance Mode),然后重启电脑
Docker实践:使用Docker搭建个人开发环境_第21张图片

3. 在容器内配置开发环境

  1. 使用docker compose命令创建容器
    在docker-compose.yml所在文件夹执行

    docker compose up -d
    

    该命令执行一次即可,重复执行会导致之前使用该命令创建的容器被删除,然后创建新的容器,数据会丢失
    容器关闭后,正确的启动方法是使用docker start命令,下文会介绍

    在前面的docker-compose.yml中,使用container_name将容器名称定义为了my_dev,因此会在主机中创建一个名为my_dev的容器

  2. 使用docker exec命令进入容器

    docker exec -it my_dev bash
    

    在哪个终端执行这个命令,那么之后在这个终端输入的命令就会在容器中执行

  3. 为容器换中科大源

    sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list && sed -i 's/security.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
    
    apt update && apt upgrade -y
    
  4. 为主机和容器安装中文语言包
    主机终端执行

    sudo apt install language-pack-zh*
    

    容器终端执行(因为容器默认用户为root,并且未安装sudo,所以命令里不需要加上sudo)

    apt install language-pack-zh*
    
  5. 在步骤1.中打开的容器终端输入 exit ,退出容器终端

    exit
    
  6. 在主机的终端中使用docker restart命令重启容器

    docker restart my_dev
    
  7. 重复步骤1.,然后在这个终端中为容器配置自己需要的环境就可以了
    若想打开更多容器内终端,同样重复步骤1.即可

    • 开发的时候会用到ssh连接容器,所以需要给容器安装openssh-server

      apt install openssh-server
      

      然后修改容器内的/etc/ssh/sshd_config文件:

      • 将 Port 解注释,并把值从22改为其他值(不能使用主机正在使用的端口,因为容器在 host 模式下与主机共用端口),比如2222
      • 找到 PermitRootLogin ,解注释并把值改为 yes

      修改容器root用户的密码

      passwd
      

4. 保存/备份容器

配完容器的环境后,需要将容器保存为镜像,这样才能复用

  1. 使用docker stop命令关闭容器

    docker stop my_dev
    
  2. 使用docker export命令将容器导出为tar包

    docker export -o=my_dev.tar my_dev
    

    -o=my_dev.tar指定了tar包的生成路径为当前文件夹且生成的包的名称为my_dev.tar,最后的参数my_dev是容器名称

  3. 使用docker import命令将tar包导入为镜像

    docker import my_dev.tar my_dev:latest
    

    这样就成功导入了镜像,可以通过docker image命令查看自己导入的镜像

    docker image ls -a
    # 另一种写法
    # docker images -a
    

    my_dev是镜像名称,latest是标签,可以理解为镜像的分支或版本,就像git中的master一样,镜像的默认标签为latest,标签可以自定义,比如my_dev:v1

  4. 将镜像推送到远程仓库
    推送到Docker Hub:Docker官方文档学习笔记(二):入门、Docker官方文档学习笔记(三):总结与补充
    推送到阿里云:使用阿里云管理Docker镜像

    简单来说就是注册账户->创建远程仓库->使用docker login本地终端登陆账户->使用docker tag修改本地镜像名称->使用docker push推送到远程仓库

5. 修改docker-compose.yml

在步骤编写docker-compose.yml中,使用的镜像是nvidia的镜像,现在要更换为自己的镜像,所以将image修改为

image: my_dev:latest

需要ssh连接容器,所以在容器启动的时候就要启动ssh服务,将command修改为

command: bash -c "service ssh start && tail -f /dev/null"

然后重新创建容器

docker compose up -d

6. 开始使用

以后每次开机后,启动自己配好的容器时,都只需要使用docker start命令

docker start my_dev

要运行GUI程序,见Docker容器运行GUI程序的方法(直接进入Docker容器运行或通过SSH连接Docker容器运行)

  • 使用vscode在容器内写代码
    安装好Remote插件后,点击左侧的远程资源管理器图标
    Docker实践:使用Docker搭建个人开发环境_第22张图片
    点击右上角的齿轮图标
    在这里插入图片描述
    点击“Settings”
    Docker实践:使用Docker搭建个人开发环境_第23张图片
    自己新建好一个空文件用于保存SSH配置

    touch ~/vscode_Remote_config
    

    然后在这里指定好路径
    Docker实践:使用Docker搭建个人开发环境_第24张图片
    点击右上角的“+”
    Docker实践:使用Docker搭建个人开发环境_第25张图片
    输入命令,按回车,选择保存在刚才新建的配置文件中

    ssh -p 2222 root@localhost -Y
    

    保存成功后配置文件如图所示,远程资源管理器中也出现了添加的连接
    Docker实践:使用Docker搭建个人开发环境_第26张图片
    右键选择连接
    Docker实践:使用Docker搭建个人开发环境_第27张图片
    如图所示连接成功
    Docker实践:使用Docker搭建个人开发环境_第28张图片
    点击左侧的扩展图标,进入扩展界面,会显示主机和容器安装的扩展,点击下载图标即可同步扩展到容器中
    Docker实践:使用Docker搭建个人开发环境_第29张图片
    这样就设置完成了,可以在容器中写代码了

  • 连接容器

    • ssh连接
      ssh -p 2222 root@localhost -Y
      
    • docker exec连接
      docker exec -it my_dev bash
      

无Nvidia独显开发环境搭建教程

适用于无Nvidia独显的主机

1. 编写Dockerfile并构建镜像

# 使用的是ubuntu18.04镜像,是Docker Hub上的Ubuntu官方镜像
FROM ubuntu:18.04

# 每一个RUN命令都会在镜像中构建一个“层”
# 从DEBIAN_FRONTEND开始往下的都是安装命令,仅为示例,非必须
RUN /bin/bash -c "sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list \ 
    && sed -i 's/security.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list \ 
    && apt update && apt upgrade -y && \
    DEBIAN_FRONTEND=noninteractive apt install tzdata git openssh-server vim zsh libgoogle-glog-dev libgflags-dev libatlas-base-dev \ 
    libeigen3-dev libsuitesparse-dev  \ 
    build-essential libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev \ 
    qt5-default qtcreator libssl-dev openssl sudo python-dev libgtest-dev net-tools inetutils-ping \ 
    usbutils x11-apps language-pack-zh* iproute2 ninja-build -y"

写好后,使用docker build命令构建镜像

docker build -t=my_dev:latest .

-t=my_dev是将构建的镜像名称指定为my_dev,版本/标签为latest,后面的“.”是指Dockerfile的路径为当前目录下

执行该命令后,Docker会从Docker Hub下载ubuntu:18.04镜像,然后在这个镜像中执行RUN所给的命令,最后构建出一个名为my_dev的镜像

2. 编写docker-compose.yml

# 这个version指的是compose文档的官方版本,不同版本号所含的功能不同
# 具体见 https://docs.docker.com/compose/compose-file/compose-versioning/
# 编写本教程时的最新版本为3.8
version: '3.8'
# 项目名称
name: my_dev
# 所有的容器的定义都要在services这个顶级元素下定义
services:
  # 服务名称,可以与项目名称保持一致
  my_dev:
    # 设置为true,则容器内PID为1的进程就会是docker提供的一个init程序
    # 这样可以使容器能够回收内部的僵尸进程,避免占用资源
    init: true
    # 容器名称,可以与服务名称保持一致
    container_name: my_dev
    # 网络模式设置为host,就可以与主机使用同一个网络,而不是使用docker虚拟网卡的桥接网络,方便设置代理和ssh连接
    network_mode: "host"
    # 设置为true,则容器内的root用户与主机的root用户具有相同的权限
    privileged: true
    image: my_dev:latest
    # 设置容器启动后自动执行的命令,不能为空
    # 容器内PID为1的进程退出后,容器就会关闭,为了防止容器自动关闭,就需要让容器一直运行程序
    # 这个命令可以防止容器启动后自动退出
    command: tail -f /dev/null
    # 设置要挂载的目录,可以理解为共享文件夹
    volumes:
      # 使容器和主机共用一套ssh密钥,但主机内该文件夹的config文件(如果存在的话)不能被容器内的root用户使用,
      # 可能会报错(Bad owner or permissions on /root/.ssh/config)。
      # 这个config文件是vscode保存ssh连接的,权限为600
      # 解决办法是将主机的这个config文件改名,例如改为config.back
      # 但推荐方法是重新设置vscode保存ssh连接的文件的路径,下文会介绍
      # - "~/.ssh:/root/.ssh:rw" # 本来是为了省事,现在不推荐挂载,因为会导致一些报错,处理起来比较麻烦。
      # 显示GUI所必须的
      - "/tmp/.X11-unix:/tmp/.X11-unix:rw"
      # 使容器可以读取到外接设备
      # 比如主机上插了一个USB相机,挂载/dev后,容器内就也可以使用该相机了
      - "/dev:/dev:rw"
      # 将docker-compose.yml所在目录下的ENVIRONMENTS文件夹(如果不存在则会自动创建一个)共享到容器中
      # 目的是方便在容器和主机间共享数据
      - "./ENVIRONMENTS:/root/ENVIRONMENTS:rw"
      # 将docker-compose.yml所在目录下的SHARE文件夹(如果不存在则会自动创建一个)共享到容器中
      # 目的是方便在容器和主机间共享数据
      - "./SHARE:/root/SHARE:rw"
      # 与主机共用git配置
      # - "~/.gitconfig:/root/.gitconfig:rw" # 这个也就不推荐挂载了
    # 设置容器的默认工作目录
    working_dir: /root
    # 设置环境变量
    environment:
      # 显示GUI所必须的
      - DISPLAY=$DISPLAY
      - QT_X11_NO_MITSHM=1
      # 将语言设置成简体中文
      - LC_ALL=zh_CN.UTF-8

和上文中的docker-compose.yml大部分内容一样,只是少了GPU设置,使用的镜像不同而已

3. 在容器内配置开发环境

  1. 使用docker compose命令创建容器
    在docker-compose.yml所在文件夹执行

    docker compose up -d
    

    该命令执行一次即可,重复执行会导致之前使用该命令创建的容器被删除,然后创建新的容器,数据会丢失
    容器关闭后,正确的启动方法是使用docker start命令,下文会介绍

    在前面的docker-compose.yml中,使用container_name将容器名称定义为了my_dev,因此会在主机中创建一个名为my_dev的容器

  2. 使用docker exec命令进入容器

    docker exec -it my_dev bash
    

    在哪个终端执行这个命令,那么之后在这个终端输入的命令就会在容器中执行

  3. 为容器换中科大源

    sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list && sed -i 's/security.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
    
    apt update && apt upgrade -y
    
  4. 为主机和容器安装中文语言包
    主机终端执行

    sudo apt install language-pack-zh*
    

    容器终端执行(因为容器默认用户为root,并且未安装sudo,所以命令里不需要加上sudo)

    apt install language-pack-zh*
    
  5. 在步骤1.中打开的容器终端输入 exit ,退出容器终端

    exit
    
  6. 在主机的终端中使用docker restart命令重启容器

    docker restart my_dev
    
  7. 重复步骤1.,然后在这个终端中为容器配置自己需要的环境就可以了
    若想打开更多容器内终端,同样重复步骤1.即可

    • 开发的时候会用到ssh连接容器,所以需要给容器安装openssh-server

      apt install openssh-server
      

      然后修改容器内的/etc/ssh/sshd_config文件:

      • 将 Port 解注释,并把值从22改为其他值(不能使用主机正在使用的端口,因为容器在 host 模式下与主机共用端口),比如2222
      • 找到 PermitRootLogin ,解注释并把值改为 yes

      修改容器root用户的密码

      passwd
      

4. 保存/备份容器

配完容器的环境后,需要将容器保存为镜像,这样才能复用

  1. 使用docker stop命令关闭容器

    docker stop my_dev
    
  2. 使用docker export命令将容器导出为tar包

    docker export -o=my_dev.tar my_dev
    

    -o=my_dev.tar指定了tar包的生成路径为当前文件夹且生成的包的名称为my_dev.tar,最后的参数my_dev是容器名称

  3. 使用docker import命令将tar包导入为镜像

    docker import my_dev.tar my_dev:latest
    

    这样就成功导入了镜像,可以通过docker image命令查看自己导入的镜像

    docker image ls -a
    # 另一种写法
    # docker images -a
    

    my_dev是镜像名称,latest是标签,可以理解为镜像的分支或版本,就像git中的master一样,镜像的默认标签为latest,标签可以自定义,比如my_dev:v1

  4. 将镜像推送到远程仓库
    推送到Docker Hub:Docker官方文档学习笔记(二):入门、Docker官方文档学习笔记(三):总结与补充
    推送到阿里云:使用阿里云管理Docker镜像

    简单来说就是注册账户->创建远程仓库->使用docker login本地终端登陆账户->使用docker tag修改本地镜像名称->使用docker push推送到远程仓库

5. 修改docker-compose.yml

在步骤编写docker-compose.yml中,使用的镜像是nvidia的镜像,现在要更换为自己的镜像,所以将image修改为

image: my_dev:latest

需要ssh连接容器,所以在容器启动的时候就要启动ssh服务,将command修改为

command: bash -c "service ssh start && tail -f /dev/null"

然后重新创建容器

docker compose up -d

6. 开始使用

以后每次开机后,启动自己配好的容器时,都只需要使用docker start命令

docker start my_dev

要运行GUI程序,见Docker容器运行GUI程序的方法(直接进入Docker容器运行或通过SSH连接Docker容器运行)

  • 使用vscode在容器内写代码
    安装好Remote插件后,点击左侧的远程资源管理器图标
    Docker实践:使用Docker搭建个人开发环境_第30张图片
    点击右上角的齿轮图标
    在这里插入图片描述
    点击“Settings”
    Docker实践:使用Docker搭建个人开发环境_第31张图片
    自己新建好一个空文件用于保存SSH配置

    touch ~/vscode_Remote_config
    

    然后在这里指定好路径
    Docker实践:使用Docker搭建个人开发环境_第32张图片
    点击右上角的“+”
    Docker实践:使用Docker搭建个人开发环境_第33张图片
    输入命令,按回车,选择保存在刚才新建的配置文件中

    ssh -p 2222 root@localhost -Y
    

    保存成功后配置文件如图所示,远程资源管理器中也出现了添加的连接
    Docker实践:使用Docker搭建个人开发环境_第34张图片
    右键选择连接
    Docker实践:使用Docker搭建个人开发环境_第35张图片
    如图所示连接成功
    Docker实践:使用Docker搭建个人开发环境_第36张图片
    点击左侧的扩展图标,进入扩展界面,会显示主机和容器安装的扩展,点击下载图标即可同步扩展到容器中
    Docker实践:使用Docker搭建个人开发环境_第37张图片
    这样就设置完成了,可以在容器中写代码了

  • 连接容器

    • ssh连接
      ssh -p 2222 root@localhost -Y
      
    • docker exec连接
      docker exec -it my_dev bash
      

常见问题与解答

在容器内使用git clone的时候报错,显示Bad owner or permissions on /root/.ssh/config

可能是因为使用vscode连接容器时没有修改SSH配置文件的存储位置,使用了默认位置,然后容器启动后将该文件挂载到了容器中

首先在容器内尝试修改权限

chmod 600 ~/.ssh/config

如果还不行,则删除该文件,按照上文教程,在vscode中指定SSH配置文件的存储位置

容器和主机间能共享文件,但是打不开/不能编辑/无法执行

这是权限问题导致的,容器内是root用户,主机使用非root权限用户当然无法访问,修改权限和所有者即可

命令前面加不加sudo取决于是使用容器中的root用户还是使用主机中的非root用户

  • 修改权限
    sudo chmod -R [所有者][用户组][其他]
    
    4:可读
    2:可写
    1:可执行
    -R:所有文件及其子目录,如果只是修改单个文件,不加-R参数
    例如修改SHARE目录及其中的文件、文件夹的权限
    sudo chmod -R 777 SHARE
    
  • 修改所有者
    chown -R [所有者]:[用户组]
    
    例如
    chown -R root:root
    

无法运行GUI程序

要运行GUI程序,见Docker容器运行GUI程序的方法(直接进入Docker容器运行或通过SSH连接Docker容器运行)

容器内环境崩了,如何恢复

  1. 先删除崩了的容器

    在docker-compose.yml所在目录执行

    docker compose down
    
  2. 创建新容器

    在docker-compose.yml所在目录执行

    docker compose up -d
    

在容器内能不能使用主机的用户

这个需要实现用户映射,见ROS官方文档中的login as yourself和The isolated way

你可能感兴趣的:(Docker,docker,个人开发,ubuntu)