--- layout: post title: "Docker 安装和使用" subtitle: "" description: "包括 Docker 的基本概念和使用方法。" excerpt: "本文描述了 Docker 的一些基本概念,并给出创建和启动容器的基本方法。" date: 2024-05-13 16:54:00 author: "Rick Chan" tags: ["Applications", "Docker"] categories: ["Software"] published: true --- ## 1. 安装 ```bash # Ubuntu sudo apt install docker.io # Manjaro sudo pacman -S docker ``` Windows 下安装直接下载安装包进行安装即可。前提是 BIOS 中已经开启虚拟化(可以在“任务个管理器”的 CPU 信息中查看到“虚拟化”是否已启用),Windows 安装有:“Hyper-V”、“Windows 虚拟机监控程序平台”和“适用于 Linux 的 Windows 子系统”。 如果没有安装,可以到:控制面板->程序->启用或关闭 Windows 功能 中进行安装。Windows 家庭版系统在该页面下可能没有 Hyper-V 选项,此时需要手动安装,复制下面内容到 bat 文件中,然后右击以管理员身份运行: ```bat pushd "%~dp0" dir /b %SystemRoot%\servicing\Packages\*Hyper-V*.mum >hyper-v.txt for /f %%i in ('findstr /i . hyper-v.txt 2^>nul') do dism /online /norestart /add-package:"%SystemRoot%\servicing\Packages\%%i" del hyper-v.txt Dism /online /enable-feature /featurename:Microsoft-Hyper-V-All /LimitAccess /ALL ``` 最后到管理员模式的 PowerShell 中执行: ```bat bcdedit /set hypervisorlaunchtype auto ``` 将 Hyper-V 设置为自动运行。再执行: ```bat wsl --update ``` 确保“适用于 Linux 的 Windows 子系统”为最新版本。 ## 2. 干掉讨厌的 sudo ```bash # 如果还没有 docker group 就添加一个 sudo groupadd docker # 将自己的登录名(${USER} )加入该 group 内。然后退出并重新登录就生效啦 sudo gpasswd -a ${USER} docker # 重启 docker 服务 sudo systemctl restart docker # 切换当前会话到新 group 或者重启 X 会话 # 注意,这一步是必须的,否则因为 groups 命令获取到的是缓存的组信息,刚添加的组信息未能生效,所以 docker images 执行时同样有错。 newgrp docker # 或者 pkill X ``` ## 3. 使用镜像源 以 USTC 镜像源为例。 ### 3.1. 使用 upstart 的系统 在配置文件 /etc/default/docker 中的 DOCKER_OPTS 中配置 Hub 地址: ```ini DOCKER_OPTS="--registry-mirror=https://docker.mirrors.ustc.edu.cn/" ``` 重新启动服务: ```bash sudo service docker restart ``` ### 3.2. 使用 systemd 的系统 在 /etc/docker 下创建 daemon.json 文件,修改其内容并重启启动 docker 相关服务: ```bash cd /etc/docker sudo touch daemon.json sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://docker.mirrors.ustc.edu.cn/"] } EOF sudo systemctl daemon-reload sudo systemctl restart docker ``` ## 4. 基本使用 Docker 的主要管理对象是镜像和容器,镜像是静态对象,保存了分层的用户数据;而容器是动态对象,可以看作镜像的运行状态,容器主要包容了 root fs。二者的关系如同程序文件与进程的关系。必须使用镜像来创建容器,一旦 Docker 加载并运行了某镜像,就为之创建一个与之对应的容器,容器至少有 stop 和 run 两个状态。使用 run 命令通过镜像创建容器后,该容器处于 run 状态,使用 exit 命令脱离容器后,容器处于 stop 状态。可以使用 start 命令将处于 stop 状态的容器再次运行起来。 如果每次都使用 run 命令从同一个镜像创建容器,会发现两个容器是完全一样的,因为他们都有相同的起始点。容器使用后,会保存当前的使用状态,但如果希望将其当前状态保存成镜像,可以使用 commit 命令。 *注意:以下 image name 为 \:\ 这种形式。* *建议先配置使用镜像源。* 以下是使用 Docker 的一些基础命令: ```bash # 从 docker hub 上搜索镜像 docker search [option] # 从 https://hub.docker.com 拉取镜像 docker pull [:tag] # 运行某镜像并为之创建容器 docker run # 运行某镜像,为之创建容器,将宿主机端口影射到容器端口,并将宿主机的某目录挂载到容器的对应目录下 docker run -it -p : -v : /bin/bash # 运行某镜像,为之创建容器,随机映射主机端口和容器端口,指定容器名称,赋予 privileged 权限,并将宿主机的某目录挂载到容器的对应目录下 docker run -it -P --name= --privileged -v : /bin/bash # 运行某镜像,为之创建容器,设置网络参数,并将宿主机的某目录挂载到容器的对应目录下 docker run -it --net= -v : /bin/bash # 允许容器访问 usb 总线,允许容器通过 adb 连接 android 设备 docker run -it -P --name= --privileged -v /dev/bus/usb:/dev/bus/usb /bin/bash # 映射 Nvidia GPU docker run -it -P --name= --privileged --device /dev/nvidia0:/dev/nvidia0 /bin/bash # 退出并关闭容器:在容器的 shell 中直接 exit # 查看正在运行的容器 docker ps # 提交针对某容器的修改,将其保存为镜像 docker commit : # 运行某已存在的容器 docker start # 连接到已运行的容器上 docker attach # 运行并连接到已存在的容器上 docker start -a # 在某已运行的容器中执行命令 docker exec -it # 迁移镜像 docker save -o docker load -i # 迁移容器 docker export -o docker import : ``` 想要退出但不关闭容器,在容器中按下 Ctrl + P + Q 组合健即可. ### 4.1. 容器操作 ```bash # 获得容器信息 docker container ls -a # 获得容器id docker container ls -a -p # 停止容器 docker container stop # 删除容器 docker container rm # 重命名容器 docker container rename # 更新容器的环境变量 docker container update --env = # 更新容器的端口映射 docker container update --publish : # 更新容器的内存限制 docker container update --memory 512m # 更新容器的 CPU 共享限制 docker container update --cpu-shares 512 ``` ### 4.2. 镜像操作 ```bash # 获得镜像信息 docker image ls -a # 获得镜像id docker image ls -a -p # 重命名镜像 docker tag : # 删除镜像 docker image rm ``` ## 5. 网络模式说明 ### 5.1. bridge 模式 Docker 容器默认使用 bridge 模式的网络。其特点如下: * 使用一个 linux bridge,默认为 docker0 * 使用 veth 对,一头在容器的网络 namespace 中,一头在 docker0 上 * 该模式下 Docker Container 不具有一个公有 IP,因为宿主机的IP地址与 veth pair 的 IP 地址不在同一个网段内 * Docker 采用 NAT 方式,将容器内部的服务监听的端口与宿主机的某一个端口 port 进行“绑定”,使得宿主机以外的世界可以主动将网络报文发送至容器内部 * 外界访问容器内的服务时,需要访问宿主机的 IP 以及宿主机的端口 port * NAT 模式由于是在三层网络上的实现手段,故肯定会影响网络的传输效率。 * 容器拥有独立、隔离的网络栈;让容器和宿主机以外的世界通过 NAT 建立通信。 ### 5.2. host 模式 Host 模式并没有为容器创建一个隔离的网络环境。而之所以称之为 host 模式,是因为该模式下的 Docker 容器会和 host 宿主机共享同一个网络 namespace,故 Docker Container 可以和宿主机一样,使用宿主机的 eth0,实现和外界的通信。换言之,Docker Container 的 IP 地址即为宿主机 eth0 的 IP 地址。其特点包括: * 这种模式下的容器没有隔离的 network namespace * 容器的 IP 地址同 Docker host 的 IP 地址 * 需要注意容器中服务的端口号不能与 Docker host 上已经使用的端口号相冲突 * host 模式能够和其它模式共存 ### 5.3. container 模式 Container 网络模式是 Docker 中一种较为特别的网络的模式。处于这个模式下的 Docker 容器会共享其他容器的网络环境,因此,至少这两个容器之间不存在网络隔离,而这两个容器又与宿主机以及除此之外其他的容器存在网络隔离。 ### 5.4. none 模式 网络模式为 none,即不为 Docker 容器构造任何网络环境。一旦 Docker 容器采用了none 网络模式,那么容器内部就只能使用 loopback 网络设备,不会再有其他的网络资源。Docker Container 的 none 网络模式意味着不给该容器创建任何网络环境,容器只能使用 127.0.0.1 的本机网络。 ## 6. 查看 Docker run 启动参数 ```bash pip install runlike runlike -p ``` ## 7. 设置容器自启动 1. 使用 docker run 命令运行时增加 --restart=always 参数即可; 2. 使用 docker-compose 命令运行时在 yml 文件中,需要自启动的 service 下增加 restart: always 项目即可; 3. 已运行的容器修改其自启动策略,执行命令: ```bash docker container update --restart= ``` ## 8. SSH X11Forwarding ### 8.1. Windows 下实现 在启动容器时需要使用 -p 参数将 ssh 端口映射到主机。 参照 [Linux SSH 服务的安装和使用](../SSH/Linux_SSH_服务的安装和使用.md) 中的方式配置并启动(使用非 systemd 方式) ssh 服务,并确保 /etc/ssh/sshd_config 中的以下变量为: ```bash PermitRootLogin yes X11Forwarding yes X11DisplayOffset 10 X11UseLocalhost no ``` 启动 MobaXterm 创建 SSH 连接到 127.0.0.1:<主机映射的容器 SSH 端口>,注意需要使能 X11-Forwarding 功能。之后通过 SSH 连接容器,注意 MobaXterm 打印的连接信息: ```bash • MobaXterm Professional Edition v22.0 • (SSH client, X server and network tools) ➤ SSH session to root@127.0.0.1 • Direct SSH : ✔ • SSH compression : ✔ • SSH-browser : ✔ • X11-forwarding : ✔ (remote display is forwarded through SSH) ➤ For more info, ctrl+click on help or visit our website. ``` 注意 X11-forwarding 一项后面是否为“✔”,如果为“x”说明容器没有正确开启 X11-forwarding。 ***本次配置 X11Forwarding 时总是出现“cannot open display”错误,原因是旧的 sshd_config 配置文件中一些变量不被支持,SSH 服务忽略这些变量时出现问题,导致 SSH X11-forwarding 功能没有正确开启,注释掉这些不支持的变量后工作正常。*** ## 9. 常用镜像 ```bash # Ubuntu docker pull ubuntu:16.04 docker pull ubuntu:18.04 docker pull ubuntu:20.04 # Nvidia CUDA docker pull nvidia/cuda:10.2-cudnn7-runtime-ubuntu16.04 # Tensorflow 1 docker pull tensorflow/tensorflow:1.11.0-py3 docker pull jupyter/tensorflow-notebook:17aba6048f44 ``` Wechat 镜像和启动方法: ```bash docker pull bestwu/wechat xhost + docker run -d --name wechat --device /dev/snd --ipc=host \ -v /tmp/.X11-unix:/tmp/.X11-unix \ -v $HOME/WeChatFiles:/WeChatFiles \ -e DISPLAY=unix$DISPLAY \ -e XMODIFIERS=@im=fcitx \ -e QT_IM_MODULE=fcitx \ -e GTK_IM_MODULE=fcitx \ -e AUDIO_GID=`getent group audio | cut -d: -f3` \ -e GID=`id -g` \ -e UID=`id -u` \ bestwu/wechat ``` ## 10. Ubuntu 的 ~/.bashrc 参考 ```bash # ~/.bashrc: executed by bash(1) for non-login shells. # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) # for examples # If not running interactively, don't do anything case $- in *i*) ;; *) return;; esac # don't put duplicate lines or lines starting with space in the history. # See bash(1) for more options HISTCONTROL=ignoreboth # append to the history file, don't overwrite it shopt -s histappend # for setting history length see HISTSIZE and HISTFILESIZE in bash(1) HISTSIZE=1000 HISTFILESIZE=2000 # check the window size after each command and, if necessary, # update the values of LINES and COLUMNS. shopt -s checkwinsize # If set, the pattern "**" used in a pathname expansion context will # match all files and zero or more directories and subdirectories. #shopt -s globstar # make less more friendly for non-text input files, see lesspipe(1) #[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" # set variable identifying the chroot you work in (used in the prompt below) if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then debian_chroot=$(cat /etc/debian_chroot) fi # set a fancy prompt (non-color, unless we know we "want" color) case "$TERM" in xterm-color|*-256color) color_prompt=yes;; esac # uncomment for a colored prompt, if the terminal has the capability; turned # off by default to not distract the user: the focus in a terminal window # should be on the output of commands, not on the prompt #force_color_prompt=yes if [ -n "$force_color_prompt" ]; then if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then # We have color support; assume it's compliant with Ecma-48 # (ISO/IEC-6429). (Lack of such support is extremely rare, and such # a case would tend to support setf rather than setaf.) color_prompt=yes else color_prompt= fi fi if [ "$color_prompt" = yes ]; then PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' else PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' fi unset color_prompt force_color_prompt # If this is an xterm set the title to user@host:dir case "$TERM" in xterm*|rxvt*) PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1" ;; *) ;; esac # enable color support of ls and also add handy aliases if [ -x /usr/bin/dircolors ]; then test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" alias ls='ls --color=auto' alias dir='dir --color=auto' alias vdir='vdir --color=auto' alias grep='grep --color=auto' alias fgrep='fgrep --color=auto' alias egrep='egrep --color=auto' fi # colored GCC warnings and errors #export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01' # some more ls aliases alias ll='ls -alF' alias la='ls -A' alias l='ls -CF' # Alias definitions. # You may want to put all your additions into a separate file like # ~/.bash_aliases, instead of adding them here directly. # See /usr/share/doc/bash-doc/examples in the bash-doc package. if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi # enable programmable completion features (you don't need to enable # this, if it's already enabled in /etc/bash.bashrc and /etc/profile # sources /etc/bash.bashrc). if ! shopt -oq posix; then if [ -f /usr/share/bash-completion/bash_completion ]; then . /usr/share/bash-completion/bash_completion elif [ -f /etc/bash_completion ]; then . /etc/bash_completion fi fi # Codespaces bash prompt theme __bash_prompt() { PS1='${debian_chroot:+($debian_chroot)}\[\033[00m\][\[\033[0;32m\]\u\[\033[00m\]:\[\033[1;31m\]\h\[\033[00m\]] \[\033[1;34m\]\W\[\033[00m\]\$ ' unset -f __bash_prompt } __bash_prompt export PROMPT_DIRTRIM=4 ```