Docker入门

Posted by whaler404 on January 25, 2024

教程

https://yeasy.gitbook.io/docker_practice

zelda

https://www.youtube.com/watch?v=hWdmCB4R4sY

https://github.com/triwinds/ns-emu-tools/releases

https://pixeldrain.com/u/rKz4XwiR

https://www.gamer520.com/57619.html

https://5vz43f.sharepoint.com/sites/free16/Shared%20Documents/Forms/AllItems.aspx?ga=1&id=%2Fsites%2Ffree16%2FShared%20Documents%2F2023%E5%B9%B4%2D05%E6%9C%88%2DGAME%2FSED&viewid=bf5d72b0%2Df3a1%2D4644%2Dbc45%2D1d18a2b7ea24

http://pan.doullse.com/games/switch/%E5%A1%9E%E5%B0%94%E8%BE%BE%E7%8E%8B%E5%9B%BD%E4%B9%8B%E6%B3%AA/TOTK%20[0100F2C0115B6000][v0].xci

docker概念

docker基于go语言开发,基于linux内核cgroup、namespace、union fs等技术

属于操作系统层面的虚拟化技术,对进程封装隔离

image-20230716173702755

runc:linux命令行工具,根据OCI容器运行时规范,创建运行容器

containerd:守护进程,管理容器生命周期,在节点上执行容器和管理镜像的最小功能集

docker在文件系统、网络互联、进程隔离上简化了容器创建和维护

传统虚拟机技术:在硬件上运行完整的os

docker技术:进程运行在宿主的内核,容器没有自己的内核硬件虚拟化

docker的优点

  • 更高效的系统资源利用

  • 更快速的启动时间

  • 一致的运行环境

  • 持续交付和部署

    使用dockerfile进行镜像构建

  • 更轻松的迁移

  • 更轻松的维护和扩展

    分层存储和镜像技术

docker组成

  • 镜像(image)

    • 操作系统分为内核和用户空间,linux内核启动后,挂载root文件系统,提供用户空间支持

    • docker镜像相当于特殊的root文件系统,包括

      • 容器运行的程序、库、资源、配置
      • 运行配置参数(匿名变量、环境变量、用户)

      不包括

      • 动态数据
    • 分层存储

      • 使用union fs技术,由多层文件系统组成
      • 一层层构建,前一层是后一层的基础
      • 每一层的改变只发生在该层构建结束前
      • 构建完后,删除某一层文件,只是标记为删除,实际还在镜像中
      • 便于复用、定制,在基础层上添加定制新的层

    镜像:文件系统、静态、分层、定制化

  • 容器(container)

    • 镜像image和容器container,相当于类和实例
    • 镜像静态,容器动态
    • 容器本质上是进程,有独立的命名空间namespace(root文件系统、网络配置、进程空间、用户ID空间)
    • 容器运行时,以镜像 为基础层,创建容器存储层,运行时读写
    • 容器存储层生存周期和容器一样,数据卷(volume)生存周期独立于容器,数据存储在数据卷

    容器:镜像实例、动态、独立命名空间、容器存储层、数据卷

  • 仓库(repository)

    • docker registry:存储、发分镜像

    • docker regidtry包含多个仓库repository,每个仓库包含多个标签tag,每个标签对应一个镜像

    • 一个仓库指明软件镜像,标签知名镜像的版本,格式为<仓库名>:<标签>

      例如ubuntu:6.04或者ubuntu:latest

    • 仓库名以两段式路径形式,说明docker registry以多用户运行

    • docker registry公开服务有官方的Docker Hub、红帽的Quay.io,国内有Docker Hub的镜像服务,如阿里云加速器等

    仓库:存储分发、命名格式(地址、仓库名、标签)、公开服务

使用镜像

获取镜像

从docker仓库获取镜像的命令

$ docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
  • docker镜像仓库渎职:<域名/ip>[:端口号],默认地址Docker Hub(docker.io)
  • 仓库名:<用户名>/<软件名>,对于Docker Hub,默认用户名为library,官方镜像
$ docker pull ubuntu:18.04

18.04: Pulling from library/ubuntu
92dc2a97ff99: Pull complete
be13a9d27eb8: Pull complete
c8299583700a: Pull complete
Digest: sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9c4361e321b26
Status: Downloaded newer image for ubuntu:18.04
docker.io/library/ubuntu:18.04
  • docker.iolibrary/ubuntu中获取标签为18.04的镜像,使用docker pull命令

    等价于docker pull docker.io/library/ubuntu:18.04

  • 从下载过程中可以看到,镜像多层存储,按层下载,结束后,给出sha256摘要

镜像加速器

网易云:https://hub-mirror.c.163.com

主流的Linux使用systemd进行服务管理,使用其配置镜像加速器

  • 先检查是否在docker.service文件中配置过镜像地址

    $ systemctl cat docker | grep '\-\-registry\-mirror'
    
    • 如果该命令有输出,那么请执行 $ systemctl cat docker 查看 ExecStart= 出现的位置,修改对应的文件内容去掉 --registry-mirror 参数及其值,并按接下来的步骤进行配置。

    • 如果以上命令没有任何输出,那么就可以在 /etc/docker/daemon.json 中写入如下内容(如果文件不存在请新建该文件):

      {
        "registry-mirrors": [
          "https://hub-mirror.c.163.com",
          "https://mirror.baidubce.com"
        ]
      }
      
  • 重新启动服务

    $ sudo systemctl daemon-reload
    $ sudo systemctl restart docker
    
  • 检查加速器是否生效

    执行 $ docker info,如果从结果中看到了如下内容,说明配置成功。

    Registry Mirrors:
     https://hub-mirror.c.163.com/
    

运行镜像

以这个镜像为基础启动并运行一个容器。

$ docker run -it --rm ubuntu:18.04 bash

root@e7009c6ce357:/# cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.1 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.1 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
  • docker run运行容器的命令
    • -i:交互式操作
    • -t:终端
    • --rm:容器推出后随之删除
    • ubuntu:18.04:指定镜像启动容器
    • bash:放在镜像名后的是命令,bash表明希望有交互式shell
  • 进入容器后,可以使用shell执行命令

  • 使用exit退出镜像

列出镜像

列出已经下载下来的镜像,可以使用 docker image ls 命令,列出所有的顶层镜像

列表包含了 仓库名标签镜像 ID创建时间 以及 所占用的空间

镜像ID对应唯一的镜像

镜像体积

  • 镜像在本地展开的大小
  • 不同镜像使用相同的基础镜像,拥有共同的层,相同的层只保存一份

通过 docker system df 命令来便捷的查看镜像、容器、数据卷所占用的空间

虚悬镜像

  • 镜像没有仓库名、标签

  • 由于新旧镜像名同名,旧镜像名被取消

    $ docker image ls -f dangling=true
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    <none>              <none>              00285df0df87        5 days ago          342 MB
    
  • 使用docker image prune删除

中间层镜像

  • 加速镜像构建,利用重复资源
  • docker image ls -a显示无标签的中间层镜像,只存在一份

列出部分镜像

  • 根据仓库名列出镜像docker image ls ubuntu

  • 根据仓库名和标签名列出镜像docker image ls ubuntu:18.04

  • 过滤器参数--filter

    $ docker image ls -f since=mongo:3.2
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    redis               latest              5f515359c7f8        5 days ago          183 MB
    nginx               latest              05a60462f8ba        5 days ago          181 MB
    

以特定格式显示

$ docker image ls --format ": "

删除本地镜像

$ docker image rm [选项] <镜像1> [<镜像2> ...]

使用ID、镜像名、摘要删除镜像

<镜像>可以是镜像短ID、镜像长ID、镜像名、镜像摘要

$ docker image rm 501#镜像短ID
$ docker image rm centos#镜像名
$ docker image ls --digests
$ docker image rm node@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228

Untagged 和 Deleted

  • 镜像的唯一标识是ID和摘要,一个镜像可以有多个标签
  • 先将满足要求的所有镜像标签都取消,因为如果仍有标签指向这个镜像,Delete行为就不会发生
  • 当某个镜像的所有标签被取消后,触发删除行为
  • 从上层向基础层方向删除,直到没有任何层依赖当前层,不会删除其他镜像共同 依赖的层
  • 以该镜像为基础的容器,应该先删除

使用docker image ls命令来配合

可以用来承接多个实体命令

使用docker image ls -q来配合docker image rm

比如删除所有仓库名为redis的镜像

$ docker image rm $(docker image ls -q redis)

删除所有在mongo:3.2之前的镜像

$ docker image rm $(docker image ls -q -f before=mongo:3.2)

利用commit理解镜像构成

使用Dockerfile定制镜像

Dockerfile指令详解

Dockerfile多阶段构建

构建多种系统架构支持的Docker镜像

其他制作镜像的方式

实现原理

操作容器

容器:独立的一个或一组应用

虚拟机:模拟运行的整套操作系统和上面运行的应用

启动

  • 基于镜像新建容器(常用)
  • 将终止状态(exited)的容器重新启动

新建并启动

$ docker run ubuntu:18.04 /bin/echo 'Hello world'
Hello world

输出“hello world”后,终止容器

$ docker run -t -i ubuntu:18.04 /bin/bash
root@af8bae53bdd3:/#

启动一个 bash 终端,允许用户进行交互

  • -t让docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输出
  • -i让容器的标准输入保持打开

使用docker run,docker在后台的标准操作:

  • 检查镜像是否存在,否则从registry下载
  • 创建启动容器
  • 分配文件系统,只读镜像层外挂载可读写层
  • 从宿主主机的网桥接口桥接虚拟接口到容器中
  • 从地址池中分配IP地址给容器
  • 执行用户程序(比如指定的bash程序)
  • 结束后容器终止

启动已终止的容器

使用docker container start命令,启动已经终止(exited)的容器

在伪终端可以使用pstop来查看进程信息

守护态运行

很多时候,docker在后台(daemon)运行,而不是直接将执行命令的结构输出在当前的宿主机下

  • 不添加-d参数

    $ docker run ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
    hello world
    hello world
    hello world
    hello world
    
  • 添加-d参数

    $ docker run -d ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
    77b2dc01fe0f3f1265df143181e7b9af5e05279a884f4776ee75350ea9d8017a
    

    容器在后台运行,但是不把结果(stdout)打印到宿主机上

    使用docker container logs [container ID or NAMES]查看

终止

docker container stop终止运行中的容器

docker container restart 命令会将一个运行态的容器终止,然后再重新启动它

进入容器

使用-d命令后,容器启动会进入后台

某些时候,要进入容器操作,使用docker execdocker attach,推荐前者

attach命令

$ docker run -dit ubuntu
243c32535da7d142fb0e6df616a3c3ada0b8ab417937c853a9e1c251f499f550

$ docker attach 243c
root@243c32535da7:/#

如果从stdin中exit,会导致容器的停止

exec命令

  • docker exec 后边可以跟多个参数

  • 只用 -i 参数时,由于没有分配伪终端,界面没有我们熟悉的 Linux 命令提示符,但命令执行结果仍然可以返回

    $ docker exec -i 69d1 bash
    ls
    bin
    boot
    dev
    ...
      
    $ docker exec -it 69d1 bash
    root@69d137adef7a:/#
    
  • 从这个 stdin 中 exit,不会导致容器的停止,推荐大家使用 docker exec

导入和导出

导出容器

使用docker export命令

$ docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                    PORTS               NAMES
7691a814370e        ubuntu:18.04        "/bin/bash"         36 hours ago        Exited (0) 21 hours ago                       test
$ docker export 7691a814370e > ubuntu.tar

导入容器快照

  • 使用docker import命令

    $ cat ubuntu.tar | docker import - test/ubuntu:v1.0
    $ docker image ls
    REPOSITORY          TAG                 IMAGE ID            CREATED              VIRTUAL SIZE
    test/ubuntu         v1.0                9d37a6082e97        About a minute ago   171.3 MB
    
  • 也可以使用URL导入

    $ docker import http://example.com/exampleimage.tgz example/imagerepo
    

注:用户既可以使用 *docker load* 导入镜像存储文件到本地镜像库,也可以使用 *docker import* 导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件保存完整记录,体积也要大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。

删除

  • 使用 docker container rm 来删除一个处于终止状态的容器
  • 要删除一个运行中的容器,可以添加 -f 参数
  • $ docker container prune清理掉所有处于终止状态的容器

访问仓库

注册服务器-仓库-标签

对于仓库地址 docker.io/ubuntu 来说,docker.io 是注册服务器地址,ubuntu 是仓库名

Docker Hub

docker search查看官方仓库中的镜像

docker pull下载镜像

推送镜像

用户在登录后,使用docker push命令将镜像推送到docker hub

$ docker tag ubuntu:18.04 username/ubuntu:18.04

$ docker image ls

REPOSITORY                                               TAG                    IMAGE ID            CREATED             SIZE
ubuntu                                                   18.04                  275d79972a86        6 days ago          94.6MB
username/ubuntu                                          18.04                  275d79972a86        6 days ago          94.6MB

$ docker push username/ubuntu:18.04

$ docker search username

NAME                      DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
username/ubuntu

私有仓库

docker-registry是构建私有镜像仓库的工具

  • 安装运行docker-registry

    使用官方的 registry 镜像来启动私有仓库。默认情况下,仓库会被创建在容器的 /var/lib/registry 目录下

    $ docker run -d -p 5000:5000 --restart=always --name registry registry
    

    通过 -v 参数来将镜像文件存放在本地的指定路径

    $ docker run -d \
        -p 5000:5000 \
        -v /opt/data/registry:/var/lib/registry \
        registry
    

    registry本质上是一个镜像,用来创建仓库容器,镜像存放在仓库容器的特定目录下

  • 在私有仓库上传、搜索、下载镜像

    使用 docker tag 来标记一个镜像,然后推送它到仓库(先改名后推送)

    例如私有仓库地址为 127.0.0.1:5000

    $ docker image ls
    REPOSITORY                        TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
    ubuntu                            latest              ba5877dc9bec        6 weeks ago         192.7 MB
    
    • 使用 docker tagubuntu:latest 这个镜像标记为127.0.0.1:5000/ubuntu:latest
    $ docker tag ubuntu:latest 127.0.0.1:5000/ubuntu:latest
    $ docker image ls
    REPOSITORY                        TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
    ubuntu                            latest              ba5877dc9bec        6 weeks ago         192.7 MB
    127.0.0.1:5000/ubuntu:latest      latest              ba5877dc9bec        6 weeks ago         192.7 MB
    
    • 使用 docker push 上传标记的镜像
    $ docker push 127.0.0.1:5000/ubuntu:latest
    The push refers to repository [127.0.0.1:5000/ubuntu]
    373a30c24545: Pushed
    a9148f5200b0: Pushed
    cdd3de0940ab: Pushed
    fc56279bbb33: Pushed
    b38367233d37: Pushed
    2aebd096e0e2: Pushed
    latest: digest: sha256:fe4277621f10b5026266932ddf760f5a756d2facd505a94d2da12f4f52f71f5a size: 1568
    
    • curl 查看仓库中的镜像
    $ curl 127.0.0.1:5000/v2/_catalog
    {"repositories":["ubuntu"]}
    
    • 先删除已有镜像,再尝试从私有仓库中下载这个镜像
    $ docker image rm 127.0.0.1:5000/ubuntu:latest
      
    $ docker pull 127.0.0.1:5000/ubuntu:latest
    Pulling repository 127.0.0.1:5000/ubuntu:latest
    ba5877dc9bec: Download complete
    511136ea3c5a: Download complete
    9bad880da3d2: Download complete
    25f11f5fb0cb: Download complete
    ebc34468f71d: Download complete
    2318d26665ef: Download complete
      
    $ docker image ls
    REPOSITORY                         TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
    127.0.0.1:5000/ubuntu:latest       latest              ba5877dc9bec        6 weeks ago         192.7 MB
    
  • 配置非https仓库地址

    • 让本网段的其他主机也能把镜像推送到私有仓库。把例如192.168.199.100:5000 这样的内网地址作为私有仓库地址

    • Docker 默认不允许非 HTTPS 方式推送镜像

    • 通过 Docker 的配置选项来取消这个限制

    • 对于使用 systemd 的系统,请在 /etc/docker/daemon.json 中写入如下内容

      {
        "registry-mirrors": [
          "https://hub-mirror.c.163.com",
          "https://mirror.baidubce.com"
        ],
        "insecure-registries": [
          "192.168.199.100:5000"
        ]
      }
      

私有仓库高级配置

Nexus3

数据管理

image-20230718235700107

数据卷

  • 数据卷 是一个可供一个或多个容器使用的特殊目录

  • 它绕过 UnionFS,可以提供很多有用的特性:

    • 数据卷 可以在容器之间共享和重用
    • 数据卷 的修改会立马生效
    • 数据卷 的更新,独立于镜像
    • 数据卷 默认会一直存在,即使容器被删除

    类似于 Linux 下对目录或文件进行 mount

    镜像中的被指定为挂载点的目录中的文件会复制到数据卷

  • 创建一个数据卷

    $ docker volume create my-vol
    

    查看数据卷

    $ docker volume ls
      
    DRIVER              VOLUME NAME
    local               my-vol
    

    查看指定数据卷

    $ docker volume inspect my-vol
    [
        {
            "Driver": "local",
            "Labels": {},
            "Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
            "Name": "my-vol",
            "Options": {},
            "Scope": "local"
        }
    ]
    
  • 启动一个挂载数据卷的容器

    docker run 命令的时候,使用 --mount 标记来将 数据卷 挂载到容器里

    创建一个名为 web 的容器,并加载一个 数据卷 到容器的 /usr/share/nginx/html 目录

    $ docker run -d -P \
        --name web \
        # -v my-vol:/usr/share/nginx/html \
        --mount source=my-vol,target=/usr/share/nginx/html \
        nginx:alpine
    
  • 查看数据卷的具体信息

    查看 web 容器的信息$ docker inspect web

    数据卷 信息在 “Mounts” Key 下面

    "Mounts": [
        {
            "Type": "volume",
            "Name": "my-vol",
            "Source": "/var/lib/docker/volumes/my-vol/_data",
            "Destination": "/usr/share/nginx/html",
            "Driver": "local",
            "Mode": "",
            "RW": true,
            "Propagation": ""
        }
    ],
    
  • 删除数据卷

    $ docker volume rm my-vol
    

    无主的数据卷可能会占据很多空间,使用

    $ docker volume prune
    

挂载主机目录

挂载一个主机目录作为数据卷

使用 --mount 标记可以指定挂载一个本地主机的目录到容器中去

$ docker run -d -P \
    --name web \
    # -v /src/webapp:/usr/share/nginx/html \
    --mount type=bind,source=/src/webapp,target=/usr/share/nginx/html \
    nginx:alpine
  • 这个功能在进行测试的时候十分方便,比如用户可以放置一些程序到本地目录中,来查看容器是否正常工作
  • 本地目录的路径必须是绝对路径
  • 挂载主机目录的默认权限是 读写

查看数据卷的具体信息

在主机里使用以下命令可以查看 web 容器的信息

$ docker inspect web

挂载一个本地主机文件作为一个数据卷

$ docker run --rm -it \
   # -v $HOME/.bash_history:/root/.bash_history \
   --mount type=bind,source=$HOME/.bash_history,target=/root/.bash_history \
   ubuntu:18.04 \
   bash

root@2affd44b4667:/# history
1  ls
2  diskutil list

使用网络

docker允许外部访问容器或者容器互联的方式来提供网络服务

外部访问容器

映射所有接口地址

  • 容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P-p 参数来指定端口映射

  • -P 标记时,Docker 会随机映射一个端口到内部容器开放的网络端口

  • 使用 docker container ls 可以看到,本地主机的 32768 被映射到了容器的 80 端口。此时访问本机的 32768 端口即可访问容器内 NGINX 默认页面

    $ docker run -d -P nginx:alpine
      
    $ docker container ls -l
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                   NAMES
    fae320d08268        nginx:alpine        "/docker-entrypoint.…"   24 seconds ago      Up 20 seconds       0.0.0.0:32768->80/tcp   bold_mcnulty
    

    通过 docker logs 命令来查看访问记录

    $ docker logs fa
    172.17.0.1 - - [25/Aug/2020:08:34:04 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0" "-"
    
  • -p 则可以指定要映射的端口

    ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort
    

映射到指定地址的指定端口

使用 ip:hostPort:containerPort 格式指定映射使用一个特定地址

$ docker run -d -p 127.0.0.1:80:80 nginx:alpine

映射到指定地址的任意端口

使用 ip::containerPort 绑定 localhost 的任意端口到容器的 80 端口,本地主机会自动分配一个端口

$ docker run -d -p 127.0.0.1::80 nginx:alpine

查看端口配置

使用 docker port 来查看当前映射的端口配置,也可以查看到绑定的地址

$ docker port fa 80
0.0.0.0:32768
  • 容器有自己的内部网络和 ip 地址(使用 docker inspect 查看,Docker 还可以有一个可变的网络配置。)

  • -p 标记可以多次使用来绑定多个端口

$ docker run -d \
    -p 80:80 \
    -p 443:443 \
    nginx:alpine

容器互联

使用 --link 参数来使容器互联

新建网络

$ docker network create -d bridge my-net

-d 参数指定 Docker 网络类型

连接容器

运行一个容器并连接到新建的 my-net 网络

$ docker run -it --rm --name busybox1 --network my-net busybox sh

打开新的终端,再运行一个容器并加入到 my-net 网络

$ docker run -it --rm --name busybox2 --network my-net busybox sh

通过 ping 来证明 busybox1 容器和 busybox2 容器建立了互联关系

busybox1 容器输入以下命令

/ # ping busybox2
PING busybox2 (172.19.0.3): 56 data bytes
64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.072 ms
64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.118 ms

配置DNS

如何自定义配置容器的主机名和 DNS 呢?秘诀就是 Docker 利用虚拟文件来挂载容器的 3 个相关配置文件

$ mount
/dev/disk/by-uuid/1fec...ebdf on /etc/hostname type ext4 ...
/dev/disk/by-uuid/1fec...ebdf on /etc/hosts type ext4 ...
tmpfs on /etc/resolv.conf type tmpfs ...

这种机制可以让宿主主机 DNS 信息发生更新后,所有 Docker 容器的 DNS 配置通过 /etc/resolv.conf 文件立刻得到更新

配置全部容器的 DNS ,也可以在 /etc/docker/daemon.json 文件中增加以下内容来设置

{
  "dns" : [
    "114.114.114.114",
    "8.8.8.8"
  ]
}

一些tips

docker中的ubuntu安装软件:https://blog.csdn.net/cecurio/article/details/105578136

cp /etc/apt/sources.list /etc/apt/sources.list.bak

echo "deb http://mirrors.ustc.edu.cn/ubuntu/ xenial main restricted universe multiverse" >/etc/apt/sources.list
echo "deb http://mirrors.ustc.edu.cn/ubuntu/ xenial-security main restricted universe multiverse" >>/etc/apt/sources.list
echo "deb http://mirrors.ustc.edu.cn/ubuntu/ xenial-updates main restricted universe multiverse" >>/etc/apt/sources.list
echo "deb http://mirrors.ustc.edu.cn/ubuntu/ xenial-proposed main restricted universe multiverse" >>/etc/apt/sources.list
echo "deb http://mirrors.ustc.edu.cn/ubuntu/ xenial-backports main restricted universe multiverse" >>/etc/apt/sources.list
echo "deb-src http://mirrors.ustc.edu.cn/ubuntu/ xenial main restricted universe multiverse" >>/etc/apt/sources.list
echo "deb-src http://mirrors.ustc.edu.cn/ubuntu/ xenial-security main restricted universe multiverse" >>/etc/apt/sources.list
echo "deb-src http://mirrors.ustc.edu.cn/ubuntu/ xenial-updates main restricted universe multiverse" >>/etc/apt/sources.list
echo "deb-src http://mirrors.ustc.edu.cn/ubuntu/ xenial-proposed main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.ustc.edu.cn/ubuntu/ xenial-backports main restricted universe multiverse" >>/etc/apt/sources.list

apt-get update 

apt-get install -y vim