Docker学习

文章目录

Docker教案

Docker的安装

直接操作的环境:https://labs.play-with-docker.com/

环境选择

容器需要管理工具、runtime 和操作系统,我们的选择如下:

  1. 管理工具 - Docker Engine,Docker 最流行使用最广泛。
  2. runtime - runc,Docker 的默认 runtime
  3. 操作系统 - CentOS Stream8

安装操作系统

基于CentOS-Stream-8模板克隆一个虚拟机命名为docker,并配置静态IP 192.168.108.30,主机名改为docker

bash 复制代码
[root@localhost ~]# hostnamectl set-hostname docker
[root@localhost ~]# nmcli connection modify ens160 ipv4.method manual ipv4.addresses 192.168.108.30/24 ipv4.gateway 192.168.108.2 ipv4.dns 192.168.108.2 autoconnect yes
[root@localhost ~]# nmcli con up ens160

安装 Docker

Docker 支持几乎所有的 Linux 发行版,也支持 Mac 和 Windows。各操作系统的安装方法可以访问:https://docs.docker.com/engine/installation/

卸载旧版本

bash 复制代码
[root@docker ~]# yum remove docker-ce

安装必要工具

bash 复制代码
[root@localhost ~]# yum install -y yum-utils device-mapper-persistent-data lvm2 vim      
[root@localhost ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
Adding repo from: https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

[root@localhost ~]# yum makecache
Docker CE Stable - x86_64                                                                             57 kB/s |  66 kB     00:01
CentOS Stream 8 - BaseOS                                                                             8.3 kB/s | 3.9 kB     00:00
CentOS Stream 8 - AppStream                                                                          9.8 kB/s | 4.4 kB     00:00
Metadata cache created.

allinone部署

安装软件

bash 复制代码
[root@docker ~]# yum install -y docker-ce

配置服务

bash 复制代码
[root@docker ~]# systemctl enable docker.service --now

验证安装

查看docker版本

bash 复制代码
[root@docker ~]# docker --version
Docker version 26.1.3, build b72abbb

验证docker状态

bash 复制代码
[root@docker ~]# systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
   Active: active (running) since Wed 2025-09-03 13:51:07 CST; 36s ago
     Docs: https://docs.docker.com
 Main PID: 1813 (dockerd)
    Tasks: 10
   Memory: 135.7M
   CGroup: /system.slice/docker.service
           └─1813 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

配置镜像加速器(华为云)

bash 复制代码
[root@docker ~]# vi /etc/docker/daemon.json
{
    "registry-mirrors": [ "https://054b8ac70e8010d90f2ac00ef29e6580.mirror.swr.myhuaweicloud.com" ]
}

[root@docker ~]# systemctl restart docker

[root@docker ~]# docker info
Client: Docker Engine - Community
 Version:    26.1.3
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.14.0
    Path:     /usr/libexec/docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.27.0
    Path:     /usr/libexec/docker/cli-plugins/docker-compose
......
 Registry Mirrors:
  `https://054b8ac70e8010d90f2ac00ef29e6580.mirror.swr.myhuaweicloud.com/   
 Live Restore Enabled: false

Docker C/S分离部署

基于CentOS-Stream-8模板克隆两个虚拟机命名为docker_client和docker_server

docker server端配置

配置ip和主机名

bash 复制代码
[root@localhost ~]# hostnamectl set-hostname docker_server
[root@localhost ~]# nmcli connection modify ens160 ipv4.method manual ipv4.addresses 192.168.108.30/24 ipv4.gateway 192.168.108.2 ipv4.dns 192.168.108.2 autoconnect yes
[root@localhost ~]# nmcli con up ens160

安装软件

bash 复制代码
[root@docker_server ~]# yum install -y yum-utils device-mapper-persistent-data lvm2 vim      
[root@localhost ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
Adding repo from: https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
[root@docker_server ~]# yum makecache
[root@docker_server ~]# yum install -y docker-ce
[root@docker_server ~]# systemctl enable docker.service --now
[root@docker_server ~]# vi /etc/docker/daemon.json
{
    "registry-mirrors": [ "https://054b8ac70e8010d90f2ac00ef29e6580.mirror.swr.myhuaweicloud.com" ]
}

[root@docker_server ~]# systemctl restart docker

配置服务

bash 复制代码
[root@docker_server ~]# vim /usr/lib/systemd/system/docker.service
# 在ExecStart参数中最后添加 -H tcp://0.0.0.0:2375,docker默认监听2375
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375

[root@docker_server ~]# systemctl daemon-reload
[root@docker_server ~]# systemctl restart docker.service
[root@docker_server ~]# systemctl stop firewalld

配置效果如下

验证

bash 复制代码
[root@docker_server ~]# yum install lsof

[root@docker_server ~]# lsof -i :2375
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
dockerd 5440 root    3u  IPv6  44991      0t0  TCP *:docker (LISTEN)

docker_client端

配置ip与主机名

bash 复制代码
[root@localhost ~]# hostnamectl set-hostname docker_client
[root@localhost ~]# nmcli connection modify ens160 ipv4.method manual ipv4.addresses 192.168.108.31/24 ipv4.gateway 192.168.108.2 ipv4.dns 192.168.108.2 autoconnect yes
[root@localhost ~]# nmcli con up ens160

只安装docker客户端

bash 复制代码
[root@docker-client ~]# yum install -y yum-utils device-mapper-persistent-data lvm2 vim      
[root@docker-client ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
Adding repo from: https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
[root@docker-client ~]# yum makecache
[root@docker-client ~]# yum install -y docker-ce-cli

验证

bash 复制代码
[root@docker_client ~]# docker run hello-world          #client直接执行报错,没有装服务端
docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?.
See 'docker run --help'.

# client端连接server端执行命令
[root@docker-client ~]# docker -H 192.168.108.30 run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.
......
 
[root@docker-client ~]# docker -H 192.168.108.30 images 
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
hello-world   latest    d2c94e258dcb   17 months ago   13.3kB

说明:client只做管理,image和container存储在server端。

Docker介绍

Docker是基于Go语言实现的开源容器项目

Docker提供了各种容器管理工具 ,让用户可以更简单明了地管理和使用容器;其次,Docker引入分层文件系统构建和高效的镜像机制降低了迁移难度,极大地提升了用户体验。

可以将Docker容器理解为一种轻量级的沙盒每个容器内运行着一个应用,不同的容器相互隔离,容器之间也可以通过网络互相通信

Docker 核心概念

Docker的大部分操作都围绕着它的三大核心概念------镜像、容器和仓库。

Docker镜像

Docker镜像类似于虚拟机镜像,镜像是创建Docker容器的基础。

Docker容器

Docker容器类似于一个轻量级的沙箱,Docker利用容器来运行和隔离应用。容器是从镜像创建的应用运行实例。容器都是彼此相互隔离的、互不可见的。

Docker仓库

Docker仓库是Docker集中存放镜像文件的场所。仓库注册服务器存放着很多类镜像,每类镜像包括多个镜像文件,通过不同的标签(tag)来进行区分。

根据所存储的镜像公开分享与否,Docker仓库可以分为:

  • 公开仓库(Public)
  • 私有仓库(Private)

Docker 架构

完整的Docker由以下几部分构成:

  • 守护进程(Daemon):Docker守护进程(dockerd)侦听Docker API请求并管理Docker对象,,如图像、容器、网络和卷。守护进程还可以与其他守护进程通信来管理Docker服务

  • REST API: 主要与Docker Daemon进行交互

  • 客户端(Docker Client): 它是与Docker交互的主要方式,通过命令行接口(CLI)客户端(docker命令),客户机将命令通过REST API发送给并执行其命令

  • Register Repository 镜像仓库: Docker注册表存储Docker镜像

  • Image 镜像: 镜像是一个只读模板,带有创建Docker容器的指令

  • Container 容器: 容器是镜像的可运行实例

  • Services : Docker引擎支持集群模式服务允许您跨多个Docker守护进程扩展管理容器,服务允许您定义所需的状态,对于使用者来说Docker服务看起来是一个单独的应用程序

Docker 架构如下图所示:

Docker 采用的是 Client/Server 架构。客户端向服务器发送请求,服务器负责构建、运行和分发容器。客户端和服务器可以运行在同一个 Host 上,客户端也可以通过 socket 或 REST API 与远程的服务器通信

镜像

最小的镜像

镜像是 Docker 容器的基石,容器是镜像的运行实例,有了镜像才能启动容器。

hello-world - 最小的镜像

hello-world 是 Docker 官方提供的一个镜像,通常用来验证 Docker 是否安装成功。

我们先通过 docker pull 从 Docker Hub 下载它。

shell 复制代码
[root@docker ~]# docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete
Digest: sha256:91fb4b041da273d5a3273b6d587d62d518300a6ad268b28628f74997b93171b2
Status: Downloaded newer image for hello-world:latest
docker.io/library/hello-world:latest

docker images 命令查看镜像的信息。

shell 复制代码
[root@docker ~]# docker images 
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
hello-world   latest    d2c94e258dcb   16 months ago   13.3kB

通过 docker run 运行。

shell 复制代码
[root@docker ~]# docker run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

.......

base镜像

base 镜像有两层含义:

  1. 不依赖其他镜像,从 scratch 构建。
  2. 其他镜像可以之为基础进行扩展。

所以,能称作 base 镜像的通常都是各种 Linux 发行版的 Docker 镜像,比如 Ubuntu, Debian, CentOS 等。

镜像的分层结构

Docker 支持通过扩展现有镜像,创建新的镜像。

Docker 镜像采用分层结构的作用:共享资源

可写的容器层

当容器启动时,一个新的可写层被加载到镜像的顶部。

这一层通常被称作"容器层","容器层"之下的都叫"镜像层"。

只有容器层是可写的,容器层下面的所有镜像层都是只读的

构建镜像

Docker 提供了两种构建镜像的方法:

  1. docker commit 命令
  2. Dockerfile 构建文件
docker commit

docker commit 包含三个步骤:

  1. 运行容器
  2. 修改容器
  3. 将容器保存为新的镜像

例子:在 ubuntu base 镜像中安装 vim并保存为新镜像。

运行容器

shell 复制代码
[root@docker ~]# docker run -it ubuntu
root@8dbdff6d3d88:/#

-it 以交互模式进入容器,并打开终端

安装 vim

shell 复制代码
root@8dbdff6d3d88:/# apt-get update
root@8dbdff6d3d8:/# apt-get install -y vim  

保存为新镜像 ubuntu-with-vim

bash 复制代码
[root@docker ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED         STATUS         PORTS     NAMES
8dbdff6d3d88   ubuntu    "/bin/bash"   2 minutes ago   Up 2 minutes             cool_darwin
shell 复制代码
[root@docker ~]# docker commit cool_darwin ubuntu-with-vim    
sha256:ba18ae460c068f9bdba060350e64dcec4bc4af05b9918602ee34e6350d0369a4

查看新镜像的属性

bash 复制代码
[root@docker ~]# docker images
REPOSITORY                   TAG       IMAGE ID       CREATED          SIZE
ubuntu-with-vim              latest    acefd029083b   27 minutes ago   189MB
ubuntu                       latest    edbfe74c41f8   5 weeks ago      78.1MB

验证

shell 复制代码
[root@docker ~]# docker run -it ubuntu-with-vim    #ubuntu-with-vim是新创建的镜像名
root@4d071cf3014f:/# which vim
/usr/bin/vim
root@4d071cf3014f:/# vim file1
Dockerfile构建镜像

Dockerfile 是一个文本文件,记录了镜像构建的所有步骤。

Dockerfile内容基础知识:

  1. 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
  2. 指令按照从上到下,顺序执行
  3. 每条指令都会创建一个新的镜像层并对镜像进行提交

常用参数:

复制代码
docker build -f [Dockerfile路径] [构建上下文路径]
参数 作用
-f--file 标志符,声明要使用自定义 Dockerfile
[Dockerfile路径] 绝对路径相对于构建上下文的路径 (如 subdir/Dockerfile.dev
[构建上下文路径] Docker 打包发送给守护进程的目录(通常用 . 表示当前目录)

使用Dockerfile 创建拥有vim功能的ubuntu镜像

bash 复制代码
[root@docker ~]# cd /root
[root@docker ~]# vim Dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y vim
[root@docker ~]# docker build -t ubuntu-with-vim-dockerfile .
  • -t 将新镜像命名为 ubuntu-with-vim-dockerfile,命令末尾的 . 指明 build context 为当前目录。Docker 默认会从 build context 中查找 Dockerfile 文件,我们也可以通过 -f 参数指定 Dockerfile 的位置。

查看镜像分层结构

ubuntu-with-vim-dockerfile 是通过在 base 镜像的顶部添加一个新的镜像层而得到的

这个新镜像层的内容由 RUN apt-get update && apt-get install -y vim 生成

docker history 会显示镜像的构建历史,也就是 Dockerfile 的执行过程。

镜像的缓存特性

Docker 会缓存已有镜像的镜像层,构建新镜像时,如果某镜像层已经存在,就直接使用,无需重新创建。

bash 复制代码
[root@docker ~]# touch testfile
[root@docker ~]# ls
Dockerfile  testfile
[root@docker ~]# vim Dockerfile
[root@docker ~]# cat Dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y vim
COPY testfile /
[root@docker ~]# docker build -t ubuntu-with-vim-dockerfile-2 .

之前已经运行过相同的 RUN 指令,这次直接使用缓存中的镜像层,在 ubuntu-with-vi-dockerfile 镜像上直接添加一层就得到了新的镜像 ubuntu-with-vim-dockerfile-2

如果我们希望在构建镜像时不使用缓存,可以在 docker build 命令中加上 --no-cache 参数

Dockerfile 中每一个指令都会创建一个镜像层,上层是依赖于下层的。只要某一层发生变化,其上面所有层的缓存都会失效;除了构建时使用缓存,Docker 在下载镜像时也会使用。

调试 Dockerfile

如果 Dockerfile 由于某种原因执行到某个指令失败了,我们也将能够得到前一个指令成功执行构建出的镜像,可以运行最新的这个镜像定位指令失败的原因

bash 复制代码
[root@docker ~]# ls             
Dockerfile  testfile
[root@docker ~]# vim Dockerfile            
FROM busybox
RUN touch tmpfile
RUN /bin/bash -c "echo continue to build..."
COPY testfile /

[root@docker ~]# docker build -t image-debug .   

Dockerfile 在执行第三步 RUN 指令时失败。我们可以利用busybox的镜像进行调试:

bash 复制代码
[root@docker ~]# vim Dockerfile
FROM busybox
RUN touch tmpfile
RUN /bin/sh -c "echo continue to builld..."         
COPY testfile /

[root@docker ~]# docker build -t image-debug .   

Dockerfile常用指令

FROM

指定 base 镜像,第一条必须是FROM

MAINTAINER

设置镜像的作者,可以是任意字符串

COPY

将文件从 build context 复制到镜像。

COPY 支持两种形式:

  1. COPY src dest
  2. COPY ["src", "dest"]

注意:src 只能指定 build context 中的文件或目录

ADD

与 COPY 类似,从 build context 复制文件到镜像。不同的是,如果 src 是归档文件(tar, zip, tgz, xz 等),文件会被自动解压到 dest

ENV

设置环境变量,环境变量可被后面的指令使用

EXPOSE

指定容器中的进程会监听某个端口

VOLUME

将文件或目录声明为 volume

WORKDIR

为后面的 RUN, CMD, ENTRYPOINT, ADD 或 COPY 指令设置镜像中的当前工作目录

RUN

在容器中运行指定的命令

CMD

容器启动时运行指定的命令;Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效;CMD 可以被 docker run 之后的参数替换

ENTRYPOINT

设置容器启动时运行的命令;Dockerfile 中可以有多个 ENTRYPOINT 指令,但只有最后一个生效;CMD 或 docker run 之后的参数会被当做参数传递给 ENTRYPOINT

编写如下的 Dockerfile:

dockerfile 复制代码
FROM busybox                     #从busybox开始构建
MAINTAINER 6946630@qq.com         #声明作者信息
WORKDIR /testdir                    #设置工作目录为/testdir
RUN touch tmpfile1                  #在新镜像中创建tmpfille1
COPY ["tmpfile2","."]               #将Dockerfile文件所在目录中的tmpfile2文件拷贝到新镜像中
ADD ["passwd.tar.gz","."]           #将Dockerfile文件所在目录中的passwd.tar.gz拷贝到新镜像中并解压缩
ENV WELCOME "You are in my container,welcome!"        #设置环境变量WELOCME
bash 复制代码
[root@docker ~]# touch tmpfile2             
[root@docker ~]# cp /etc/passwd .              
[root@docker ~]# tar -cvzf passwd.tar.gz passwd      
passwd
[root@docker ~]# rm passwd                  
[root@docker ~]# vim Dockerfile         
FROM busybox
MAINTAINER 6946630@qq.com
WORKDIR /testdir
RUN touch tmpfile1
COPY ["tmpfile2","."]
ADD ["passwd.tar.gz","."]
ENV WELCOME "You are in my container,welcome!"

[root@docker ~]# ls                       
Dockerfile  passwd.tar.gz  tmpfile2

[root@docker ~]# docker build -t my-image .    

运行容器,验证镜像内容:

RUN 、 CMD 和 ENTRYPOINT 区别

  • RUN 执行命令并创建新的镜像层,RUN 经常用于安装软件包。
  • CMD 设置容器启动后默认执行的命令及其参数,但 CMD 能够被 docker run 后面跟的命令行参数替换。
  • ENTRYPOINT 配置容器启动时运行的命令。
Shell 和 Exec 格式

我们可用两种方式指定 RUN、CMD 和 ENTRYPOINT 要运行的命令:Shell 格式和 Exec 格式

Shell 格式

dockerfile 复制代码
RUN apt-get install python3  

CMD echo "Hello world"  

ENTRYPOINT echo "Hello world" 

当指令执行时,shell 格式底层会调用 /bin/sh -c 命令

dockerfile 复制代码
[root@docker ~]# vim Dockerfile
FROM busybox
ENV name stj 
ENTRYPOINT echo "Hello, $name" 

测试

bash 复制代码
[root@docker ~]# docker build -t dockerfile1 .
[root@docker ~]# docker run dockerfile1
Hello,stj

:环境变量 name 已经被值 stj 替换。

Exec 格式

dockerfile 复制代码
RUN ["apt-get", "install", "python3"]  

CMD ["/bin/echo", "Hello world"]  

ENTRYPOINT ["/bin/echo", "Hello world"]

当指令执行时,会直接调用 命令,不会被 shell 解析

dockerfile 复制代码
[root@docker ~]# vim Dockerfile
FROM busybox
ENV name stj  
ENTRYPOINT ["/bin/echo", "Hello, $name"]

测试

bash 复制代码
[root@docker ~]# docker build -t dockerfile2 .
[root@docker ~]# docker run dockerfile2
hello,$name

:环境变量"name"没有被替换。

如果希望使用环境变量,照如下修改:

dockerfile 复制代码
[root@docker ~]# vim Dockerfile
FROM busybox
ENV name stj  
ENTRYPOINT ["/bin/sh", "-c", "echo Hello, $name"]

CMD 和 ENTRYPOINT 推荐使用 Exec 格式,因为指令可读性更强,更容易理解;RUN 则两种格式都可以。

RUN

RUN 指令通常用于安装应用和软件包。

RUN 在当前镜像的顶部执行命令,并通过创建新的镜像层。Dockerfile 中常常包含多个 RUN 指令。

RUN 有两种格式:

  1. Shell 格式:RUN
  2. Exec 格式:RUN ["executable", "param1", "param2"]
dockerfile 复制代码
[root@docker ~]# vim Dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y \  
bzr \
cvs \
git \
mercurial \
subversion

注意:apt-get update 和 apt-get install 被放在一个 RUN 指令中执行,这样能够保证每次安装的是最新的包;如果 apt-get install 在单独的 RUN 中执行,则会使用 apt-get update 创建的镜像层,而这一层可能是很久以前缓存的。

CMD

CMD 指令允许用户指定容器的默认执行的命令。

此命令会在容器启动且 docker run 没有指定其他命令时运行。

CMD 有三种格式:

  1. Exec 格式:CMD ["executable","param1","param2"] 这是 CMD 的推荐格式
  2. CMD ["param1","param2"] 为 ENTRYPOINT 提供额外的参数,此时 ENTRYPOINT 必须使用 Exec 格式
  3. Shell 格式:CMD command param1 param2
dockerfile 复制代码
[root@docker ~]# vim Dockerfile
FROM busybox
CMD echo "Hello,world"

测试

bash 复制代码
[root@docker ~]# docker build -t dockerfile5 .
[root@docker ~]# docker run -it dockerfile5
Hello,world

[root@docker ~]# docker run -it dockerfile5 /bin/sh
/ #
ENTRYPOINT

ENTRYPOINT 指令可让容器以应用程序或者服务的形式运行。

ENTRYPOINT 不会被忽略,一定会被执行,即使运行 docker run 时指定了其他命令。

ENTRYPOINT 有两种格式:

  1. Exec 格式:ENTRYPOINT ["executable", "param1", "param2"] 这是 ENTRYPOINT 的推荐格式
  2. Shell 格式:ENTRYPOINT command param1 param2

在为 ENTRYPOINT 选择格式时必须小心,因为这两种格式的效果差别很大。

Exec 格式

ENTRYPOINT 的 Exec 格式用于设置要执行的命令及其参数,同时可通过 CMD 提供额外的参数。

ENTRYPOINT 中的参数始终会被使用,而 CMD 的额外参数可以在容器启动时动态替换掉:

dockerfile 复制代码
[root@docker ~]# vim Dockerfile
FROM busybox
ENTRYPOINT ["/bin/echo", "Hello"]
CMD ["world"]

测试

bash 复制代码
[root@docker ~]# docker build -t dockerfile6 .
[root@docker ~]# docker run -it dockerfile6
Hello world
[root@docker ~]# docker run -it dockerfile6 stj
Hello stj

Shell 格式

ENTRYPOINT 的 Shell 格式会忽略任何 CMD 或 docker run 提供的参数:

dockerfile 复制代码
FROM busybox
ENTRYPOINT echo "Hello,"
CMD ["world"]

测试

bash 复制代码
[root@docker ~]# docker build -t dockerfile7 .
[root@docker ~]# docker run -it dockerfile7
Hello,
[root@docker ~]# docker run -it dockerfile7 stj
Hello,
案例1:配置SSH镜像

制作一个带SSH功能的centos镜像

创建 dockerfile

bash 复制代码
[root@docker ~]# vim centos.ssh.dockerfile
FROM centos:8.4.2105
RUN minorver=8.4.2105 && \
sed -e "s|^mirrorlist=|#mirrorlist=|g" \
-e "s|^#baseurl=http://mirror.centos.org/\$contentdir/\$releasever|baseurl=https://mirrors.aliyun.com/centos-vault/$minorver|g" \
-i.bak \
/etc/yum.repos.d/CentOS-*.repo
RUN yum install -y openssh-server
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
RUN ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key
RUN echo "root:huawei" | chpasswd
EXPOSE 22
CMD ["/usr/sbin/sshd","-D"]

构建镜像

bash 复制代码
[root@docker ~]# docker build -t centos:ssh -f centos.ssh.dockerfile .                                                       

查看镜像创建过程

bash 复制代码
[root@docker ~]# docker history centos:ssh
IMAGE          CREATED             CREATED BY                                      SIZE      COMMENT
cc138c4d3c36   36 seconds ago      CMD ["/usr/sbin/sshd" "-D"]                     0B        buildkit.dockerfile.v0
<missing>      36 seconds ago      EXPOSE map[22/tcp:{}]                           0B        buildkit.dockerfile.v0
<missing>      36 seconds ago      RUN /bin/sh -c echo "root:huawei" | chpasswd...   1.77kB    buildkit.dockerfile.v0
......

测试

bash 复制代码
[root@docker ~]# docker run -d -p 2022:22 --name sshtest centos:ssh
73d963d15407a1e73097540bb320b9edf05b468001bd707abf01bc7be5e54bcb

[root@docker ~]# docker ps
CONTAINER ID   IMAGE        COMMAND               CREATED         STATUS         PORTS                                   NAMES
73d963d15407   centos:ssh   "/usr/sbin/sshd -D"   6 seconds ago   Up 5 seconds   0.0.0.0:2022->22/tcp, :::2022->22/tcp   sshtest

[root@docker ~]# ssh root@localhost -p 2022
The authenticity of host '[localhost]:2022 ([::1]:2022)' can't be established.
ECDSA key fingerprint is SHA256:z1owYLOuClnbPrZwXxgy1jcItQT1k+QX6LxosydT64A.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[localhost]:2022' (ECDSA) to the list of known hosts.
root@localhost's password:
"System is booting up. Unprivileged users are not permitted to log in yet. Please come back later. For technical details, see pam_nologin(8)."
[root@73d963d15407 ~]#
案例2:自定义httpd镜像

创建dockerfile

bash 复制代码
[root@docker ~]# vim httpd.dockerfile
FROM centos:8.4.2105
RUN minorver=8.4.2105 \
&& sed -e "s|^mirrorlist=|#mirrorlist=|g" -e "s|^#baseurl=http://mirror.centos.org/\$contentdir/\$releasever|baseurl=https://mirrors.aliyun.com/centos-vault/$minorver|g" -i.bak /etc/yum.repos.d/CentOS-*.repo
RUN yum install -y httpd && yum clean all && rm -rf /var/cache/yum
COPY index.html /var/www/html/
EXPOSE 80
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]

[root@docker ~]# echo Hello World > index.html

构建镜像

bash 复制代码
[root@docker ~]# docker build -t httpd:centos -f httpd.dockerfile .

查看现象

bash 复制代码
[root@docker ~]# docker history httpd:centos

测试

bash 复制代码
[root@docker ~]# docker run -d -p 80:80 --name myweb httpd:centos
1e0b0631cf708bcc0a162d56b936a12cd06c9bcdebcc2594b23c2fbee3ed8894

[root@docker ~]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS              PORTS                                   NAMES
1e0b0631cf70   httpd:centos   "/usr/sbin/httpd -DF..."   About a minute ago   Up About a minute   0.0.0.0:80->80/tcp, :::80->80/tcp       myweb

[root@docker ~]# curl localhost
Hello World

镜像命名

镜像的名字由两部分组成:repository 和 tag。

[image name] = [repository]:[tag]

如果执行 docker build 时没有指定 tag,会使用默认值 latest,相当于:

docker build -t ubuntu-with-vim:latest

tag 使用

每个 repository 可以有多个 tag,而多个 tag 可能对应的是同一个镜像。

docker tag 给镜像打 tag

bash 复制代码
docker tag myimage-v1.9.1 myimage:1

docker tag myimage-v1.9.1 myimage:1.9

docker tag myimage-v1.9.1 myimage:1.9.1

docker tag myimage-v1.9.1 myimage:latest

公共仓库-dockerhub

Docker仓库是Docker集中存放镜像文件的场所;仓库存放着很多类镜像,每类镜像包括多个镜像文件,通过不同的标签(tag)来进行区分。

使用公共仓库-华为云

操作流程:




复制登录指令,回到docker上登陆

bash 复制代码
[root@docker ~]# docker login -u cn-east-3@HST3WGZY13FUUTQ9ZC32 -p b8e7d74da04a90cb0b1ac08ff894cebe6a8fc039f494dedd08cbc64095761aab swr.cn-east-3.myhuaweicloud.com
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

上传镜像

格式

bash 复制代码
docker tag {镜像名称}:{版本名称} swr.cn-east-3.myhuaweicloud.com/{组织名称}/{镜像名称}:{版本名称}
docker push swr.cn-east-3.myhuaweicloud.com/{组织名称}/{镜像名称}:{版本名称}

例:

bash 复制代码
[root@docker ~]# docker images httpd:centos
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
httpd        centos    973cac3a687f   4 hours ago   288MB

[root@docker ~]# docker tag httpd:centos swr.cn-east-3.myhuaweicloud.com/stj/centos_httpd:v1
[root@docker ~]# docker images
REPOSITORY                                                 TAG        IMAGE ID       CREATED         SIZE
httpd                                                      centos     973cac3a687f   4 hours ago     288MB
swr.cn-east-3.myhuaweicloud.com/stj/centos_httpd   v1         973cac3a687f   4 hours ago     288MB

[root@docker ~]# docker push swr.cn-east-3.myhuaweicloud.com/stj/centos_httpd:v1
The push refers to repository [swr.cn-east-3.myhuaweicloud.com/gaoqiaodong/centos_httpd]
63f254ce601f: Pushed
ca98143f89dc: Pushed
7d3485567b78: Pushed
717a93ee4ccf: Pushed
74ddd0ec08fa: Layer already exists
v1: digest: sha256:49c69273c49ab25e17ad54d2bb74412ae09a699dc3ee91f72c1cef9ba8ce405e size: 1363

搭建本地仓库

Registry

启动 registry 容器。

shell 复制代码
[root@docker ~]# docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:2

-d 是后台启动容器

-p 将容器的 5000 端口映射到 Host 的 5000 端口,5000 是 registry 服务端口

-v 将容器 /var/lib/registry 目录映射到 Host 的 /myregistry,用于存放镜像数据

docker tag 重命名镜像

bash 复制代码
[root@docker ~]# docker images
REPOSITORY                                                TAG        IMAGE ID       CREATED         SIZE
httpd                                                     latest     5daf6a4bfe74   2 months ago    148MB

[root@docker ~]# docker tag httpd:latest localhost:5000/httpd:v1
[root@docker ~]# docker images
REPOSITORY                                                TAG        IMAGE ID       CREATED         SIZE
httpd                                                     latest     5daf6a4bfe74   2 months ago    148MB
localhost:5000/httpd                                      v1         5daf6a4bfe74   2 months ago    148MB

repository 的完整格式为:[registry-host]:[port]/[username]/xxx

只有 Docker Hub 上的镜像可以省略 [registry-host]:[port]

上传镜像。

bash 复制代码
[root@docker ~]# docker push localhost:5000/httpd:v1
......

[root@docker httpd]# curl http://localhost:5000/v2/_catalog
{"repositories":["httpd"]}
企业级私有仓库 Harbor

Harbor 是构建企业级私有docker镜像的仓库的开源解决方案,它是Docker Registry的更高级封装,除了提供友好的Web UI界面,角色和用户权限管理,用户操作审计等功能外,它还整合了K8s的插件(Add-ons)仓库。

harbor下载:https://github.com/goharbor/harbor/releases

下载

bash 复制代码
[root@docker ~]# wget https://github.com/goharbor/harbor/releases/download/v2.9.1/harbor-offline-installer-v2.9.1.tgz
[root@docker ~]# tar -xvf harbor-offline-installer-v2.9.1.tgz

导入 Harbor 镜像

bash 复制代码
[root@docker ~]# mkdir /opt/harbor
[root@docker ~]# mv harbor/* /opt/harbor/
[root@docker ~]# cd /opt/harbor/
[root@docker harbor]# docker load -i harbor.v2.9.1.tar.gz     

修改 Harbor 配置文件

bash 复制代码
[root@docker harbor]# cp -ar harbor.yml.tmpl harbor.yml
[root@docker harbor]# vim harbor.yml

hostname:设置 IP

https: # 注释掉

harbor_admin_password: harbor 登录密码

更新并安装

bash 复制代码
[root@docker harbor]# ./prepare
[root@docker harbor]# ./install.sh

登录WEB界面

使用

按照步骤将一个镜像推送到 Harbor 中:

在用户管理中创建名称为 images_admin 的用户:

在项目中创建名称为cloud的项目,并添加 images_admin 为项目管理员


将内网服务器 IP 和端口配置到 daemon.json 文件中

bash 复制代码
[root@docker ~]# vim /etc/docker/daemon.json
{
    "insecure-registries": ["192.168.108.30"],
    "registry-mirrors": [ "https://054b8ac70e8010d90f2ac00ef29e6580.mirror.swr.myhuaweicloud.com" ]
}

# 重启安装
[root@docker ~]# systemctl restart docker
[root@docker harbor]# ./install.sh

登录服务器

bash 复制代码
[root@docker ~]# docker login 192.168.108.30

登录后家目录下会有一个.docker文件夹

bash 复制代码
[root@docker ~]# cd ~/.docker/
[root@docker .docker]# cat config.json
{
        "auths": {
                "192.168.108.30": {
                        "auth": "aW1hZ2VzX2FkbWluOkNsb3VkMTIjJA=="
                },
                "swr.cn-north-4.myhuaweicloud.com": {
                        "auth": "Y24tbm9ydGgtNEBMUVhBVjU4MENES1A3SUoxTDREMzpmM2NlMTJlODY4ODVkN2JkZWZlYmFiMWI1N2RmZDBiYjJiM2MxZTEyNjUxYWQ1ZTk1ODY1Nzg4MTczYzI4OTJj"
                }
        }
}

上传镜像

bash 复制代码
[root@docker .docker]# docker tag nginx:latest 192.168.108.30/cloud/nginx:latest
[root@docker .docker]# docker push 192.168.108.30/cloud/nginx:latest

下载镜像

bash 复制代码
[root@docker .docker]# docker pull 192.168.108.30/cloud/nginx

卸载harbor

bash 复制代码
[root@docker ~]# cd /opt/harbor/
[root@docker harbor]# docker compose down
......

# 清理镜像
[root@docker harbor]# docker images |grep harbor|awk '{print $1":"$2}' | xargs docker rmi

# 清理harbor使用的目录,由prepare脚本定义
[root@docker harbor]# rm -rf /data

删除软件包

bash 复制代码
[root@docker opt]# cd
[root@docker ~]# ls
anaconda-ks.cfg  harbor  harbor-offline-installer-v2.9.1.tgz
[root@docker ~]# rm -f harbor-offline-installer-v2.9.1.tgz
[root@docker ~]# rm -rf /opt/harbor/

Docker镜像小结

images 显示镜像列表

history 显示镜像构建历史

commit 从容器创建新镜像

build 从 Dockerfile 构建镜像

tag 给镜像打 tag

pull 从 registry 下载镜像

push 将 镜像 上传到 registry

rmi 删除 Docker host 中的镜像

search 搜索 Docker Hub 中的镜像

保存本地镜像为文件-save

docker默认使用overlay2存储驱动存储镜像,镜像存储在本地/var/lib/docker/overlay2

bash 复制代码
[root@docker ~]# docker info | grep 'Storage Driver'
 Storage Driver: overlay2

示例:

bash 复制代码
# 将 httpd 镜像保存为 httpd.tar
[root@docker ~]# docker save httpd -o httpd.tar         
[root@docker ~]# ls
httpd.tar  
将本地镜像文件导入本地-load

示例:

bash 复制代码
[root@docker ~]# docker images         
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

[root@docker ~]# docker load -i httpd.tar
[root@docker ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
httpd         latest    90f191b9781e   11 days ago    148MB

说明:如果本地镜像名与导入的镜像重名,则本地的镜像会被覆盖。

bash 复制代码
[root@docker ~]# docker rm -f $(docker ps -aq)      #删除所有容器
[root@docker ~]# docker rmi -f $(docker images -aq)   #删除所有镜像

容器

什么是容器

容器是一种轻量级、可移植、自包含的软件打包技术,使应用程序可以在几乎任何地方以相同的方式运行。容器无需任何修改就能够在生产系统的虚拟机、物理服务器或公有云主机上运行。

容器与虚拟机

容器由两部分组成:

  1. 应用程序本身
  2. 依赖:比如应用程序需要的库或其他软件

容器在 Host 操作系统的用户空间中运行,与操作系统的其他进程隔离。这一点显著区别于的虚拟机。

下图展示了二者的区别:

容器 虚拟机
启动速度 秒甚至毫秒启动 数秒至数十秒
系统内核 共享内核 不共享内核
实现技术 利用Linux内核技术Namespace/Cgroup等实现。 依赖虚拟化技术实现,由Hypervisor层实现对资源的隔离
隔离效果 进程级别的隔离 系统资源级别的隔离
资源消耗(性能) 容器中的应用只是宿主机上的一个普通进程 使用虚拟化技术,就会有额外的资源消耗和占用
资源调用 (敏捷性) 应用进程直接由宿主机OS管理 应用进程需经过Hypervisor的拦截和处理,才能调用系统资源
运行数量 一台服务器上能启动1000+容器 一台服务器上一般不超过100台虚拟机
应用 DevOps、微服务等 用于硬件资源划分
镜像 分层镜像 非分层镜像

如图所示,由于所有的容器共享同一个 Host OS,这使得容器在体积上要比虚拟机小很多。另外,启动容器不需要启动整个操作系统,所以容器部署和启动速度更快,开销更小,也更容易迁移。

容器的作用

容器使软件具备了超强的可移植能力

  • 容器解决的问题

Docker 将集装箱思想运用到软件打包上,为代码提供了一个基于容器的标准化运输系统。

Docker 可以将任何应用及其依赖打包成一个轻量级、可移植、自包含的容器。容器可以运行在几乎所有的操作系统上。

  • 容器的优势

    • 对于开发人员 :容器意味着环境隔离和可重复性。开发人员只需为应用创建一次运行环境,然后打包成容器便可在其他机器上运行。另外,容器环境与所在的 Host 环境是隔离的,就像虚拟机一样,但更快更简单。

    • 对于运维人员:只需要配置好标准的 runtime 环境,服务器就可以运行任何容器。这使得运维人员的工作变得更高效,一致和可重复。容器消除了开发、测试、生产环境的不一致性。

运行容器

  • 指定容器的三种方法:

    • 短ID
    • 长ID
    • 容器名称,可通过 --name 为容器命名;重命名容器可执行docker rename
  • 容器按用途可分为两类:

    • 服务类容器
    • 工具类容器

docker run=docker create + docker start

docker run 是启动容器的方法,可用三种方式指定容器启动时执行的命令:

  1. CMD 指令。
  2. ENTRYPOINT 指令。
  3. docker run 命令行中指定。

让容器长期运行

bash 复制代码
[root@docker ~]# docker run ubuntu /bin/bash -c "while true ; do sleep 1 ; echo hahaha; done"

-d 以后台方式启动容器

bash 复制代码
[root@docker ~]# docker run -d ubuntu /bin/bash -c "while true ; do sleep 1 ; echo hahaha; done"
2a0bfa267fe146753b4fc8b23d55b08fbe3a5f9b5e093de6885133f6bbd20c56

通过 "长ID"、"短ID" 或者 "名称" 来指定要操作的容器:

bash 复制代码
[root@docker ~]# docker stop 081be2bc2e1d
081be2bc2e1d

进入容器

  • 有两种方法进入容器:attachexec
docker attach

通过 docker attach 可以 attach 到容器启动命令的终端

bash 复制代码
[root@docker ~]# docker run -d ubuntu /bin/bash -c "while true ; do sleep 1 ; echo I_am_in_container ; done"
dc508b94447f83b46080267580607569a187fcc7f780433f646e9d66949731a6

[root@docker ~]# docker attach dc508b94447f83b46080267580607569a187fcc7f780433f646e9d66949731a6
I_am_in_container
I_am_in_container

:可通过 Ctrl+p 然后 Ctrl+q 组合键退出 attach 终端

docker exec

通过 docker exec 进入相同的容器:

  • -it 以交互模式打开一个 bash 终端

  • 执行 exit 退出容器,回到 docker host

  • docker exec -it <container> bash|sh 是执行 exec 最常用的方式

attach 与 exec 区别
  • attach 直接进入容器 启动命令 的终端,不会启动新的进程
  • exec 则是在容器中打开新的终端,并且可以启动新的进程
  • 如果想直接在终端中查看启动命令的输出,用 attach;其他情况使用 exec

如果只是为了查看启动命令的输出,可以使用 docker logs 命令:

bash 复制代码
[root@docker ~]# docker logs -f dc508b94447f
I_am_in_container
I_am_in_container
I_am_in_container

限制容器对内存的使用

docker 通过 cgroup 来控制容器使用的资源配额,包括 CPU、内存、磁盘三大方面,基本覆盖了常见的资源配额和使用量控制。

可以使用 stress 工具来测试 CPU 和内存

使用 Dockerfile 创建一个基于 Ubuntu 的 stress 工具镜像

bash 复制代码
[root@docker dockerfile]# vim Dockerfile
FROM ubuntu
RUN apt-get -y update && apt-get -y install stress
ENTRYPOINT ["/usr/bin/stress"]      # 以服务或进程的形式运行

[root@docker ~]# docker build -t ubuntu-with-stress .

内存限额

容器可使用的内存包括两部分:物理内存swap

  • -m--memory:设置内存的使用限额
  • --memory-swap:设置 内存+swap 的使用限额

docker run -m 200M --memory-swap=300M ubuntu

其含义是允许该容器最多使用 200M 的内存和 100M 的 swap

如果--memory-swap 设置为0 或者不设置,则容器可以使用的swap大小为-m值的两倍。

如果 --memory-swap 的值和-m 值相同,则容器不能使用swap

如果 --memory-swap值为-1。它表示容器程序使用的内存受限,而可以使用的swap空间不受限制(宿主机有多少swap空间该容器就可以使用多少)
压力测试

bash 复制代码
[root@docker ~]# docker run -it -m 200M --memory-swap=300M ubuntu-with-stress --vm 1 --vm-bytes 280M -v
  • --vm 1:启动 1 个内存工作线程

  • --vm-bytes 280M:每个线程分配 280M 内存

限制容器对CPU的使用

Docker 可以通过 -c--cpu-shares 设置容器使用 CPU 的权重;如果不指定,默认值为 1024

--cpu-shares 的值不能保证可以获得1个 vcpu 或者多少 GHz 的 CPU 资源,仅仅只是一个弹性的加权值

:这种按权重分配 CPU 只会发生在 CPU 资源紧张的情况下

启动 container_A,cpu share 为 1024

bash 复制代码
[root@docker ~]# docker run --name "container_A" -it -c 1024 ubuntu-with-stress --cpu 4 -v
  • --cpu 用来设置工作线程的数量

启动 container_B,cpu share 为 512

bash 复制代码
[root@docker ~]# docker run --name "container_B" -it -c 512 ubuntu-with-stress --cpu 4 -v

查看容器对 CPU 的使用情况

容器的导入导出

export-导出容器
  • 不管容器是否处于运行状态,都可以导出为文件
bash 复制代码
[root@docker ~]# docker run -d --name httpd1 httpd
e4f0a329c4df50ef0afb0bf21e22edc20e5a24c03ae64c6340aa2992d6e32525

[root@docker ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND              CREATED         STATUS         PORTS                 NAMES
e4f0a329c4df   httpd     "httpd-foreground"   3 minutes ago   Up 3 minutes   80/tcp                httpd1

[root@docker ~]# docker export httpd1 -o myhttpd.tar
[root@docker ~]# ls
myhttpd.tar
import-导入容器
bash 复制代码
[root@docker ~]# docker import myhttpd.tar
sha256:9ae4699fa217a7240c73a50e93a8c1d359d22cf60869d350c8aab8b3c02aabcf

[root@docker ~]# docker import myhttpd.tar myweb:v1
sha256:9fcb90561d2014130ef19f9dd8af5efd7a0a4a2154907bc818ac6b887f13755c

[root@docker ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
myweb         v1        9fcb90561d20   3 seconds ago    146MB
<none>        <none>    9ae4699fa217   32 seconds ago   146MB

docker savedocker export对比:

  • docker save:将镜像保存为文件,save会保存该镜像的所有元数据和历史记录。
  • docker export:将容器导出为文件,文件会丢失所有元数据和历史记录,仅保存容器当时的状态,再次导入会当作全新的镜像。

网络

none、host和bridge网络

Docker 安装时会自动在 host 上创建三个网络,我们可用 docker network ls 命令查看:

bash 复制代码
[root@docker ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
a1b809382f0d   bridge    bridge    local
6ad21ed9ea1f   host      host      local
4e31521b27c6   none      null      local
none 网络

挂在none网络上的容器只有lo,无法与外界通信

容器创建时,可以通过 --network=none 指定使用 none 网络

bash 复制代码
[root@docker ~]# docker run -it --network=none busybox
/ # ifconfig
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

一些对安全性要求高并且不需要联网的应用可以使用 none 网络

host 网络

连接到 host 网络的容器共享 Docker host 的网络栈,容器的网络配置与 host 完全一样

通过 --network=host 指定使用 host 网络

bash 复制代码
[root@docker ~]# docker run -it --network=host busybox      
/ # ip l
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq qlen 1000
    link/ether 00:0c:29:33:15:f6 brd ff:ff:ff:ff:ff:ff
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue
    link/ether 02:42:02:fd:82:b3 brd ff:ff:ff:ff:ff:ff
/ #
/ # hostname                               #容器主机与宿主机相同
docker
/ #

如果容器对网络传输效率有较高要求,则可以选择 host 网络

brige 网络

Docker 安装时会创建一个 命名为 docker0 的 linux bridge,实际上它是 Linux 的一个 bridge (网桥),可以理解为一个软件交换机,它会在挂载到它的网口之间进行转发。如果不指定--network,创建的容器默认都会挂到 docker0 上。

当创建一个 Docker 容器的时候,同时会创建了一对 veth pair 接口,通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。

配置yum源,安装软件

bash 复制代码
[root@docker ~]# cd /etc/yum.repos.d/
[root@docker yum.repos.d]# vim cloud.repo
[centos-openstack-victoria]
name=CentOS 8 - OpenStack victoria
baseurl=https://mirrors.aliyun.com/centos-vault/8-stream/cloud/x86_64/openstack-victoria/
enabled=1
gpgcheck=0

[root@docker yum.repos.d]# yum install -y bridge-utils
[root@docker ~]# brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.02420be905a5       no

创建容器查看变化

bash 复制代码
[root@docker ~]# docker run -itd --name busybox1 busybox
5225d246f751dbfc4cdf745675d9c79d3de1b91dd4174268c35e671b9f1b0c80

[root@docker ~]# brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.02420be905a5       no              vethddb2744

一个新的网络接口 vethddb2744 被挂到了 docker0 上,vethddb2744就是新创建容器的虚拟网卡

查看容器的网络配置

bash 复制代码
[root@docker ~]# docker exec -it busybox1 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
       
# 容器里的网卡是24号网卡名字叫eth0,对面是25号网卡
24: eth0@if25: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

自定义容器网络

用户可以根据业务需要创建 user-defined 网络

我们可通过 bridge 驱动创建类似前面默认的 bridge 网络,例如:

bash 复制代码
[root@docker ~]# docker network create --driver bridge my_net
89f7bc11b602e84452ae01786113ac196a535f7296b9989ad941b3a48a5e6d04

查看当前 host 的网络

bash 复制代码
[root@docker ~]# brctl show
bridge name              bridge id               STP enabled     interfaces
br-89f7bc11b602         8000.0242194d039e         no          
docker0                 8000.02420be905a5         no             vethddb2744                

执行 docker network inspect 查看一下 my_net 的配置信息:

bash 复制代码
[root@docker ~]# docker network inspect my_net
......
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
......

这里 172.18.0.0/16 是 Docker 自动分配的 IP 网段

创建网段时指定 --subnet--gateway 参数

bash 复制代码
[root@docker ~]# docker network create --driver bridge --subnet 172.22.16.0/24 --gateway 172.22.16.1 my_net2
ec761bc51778f67c2245af72fd969f00cd517ee617a10a70dc01904f9c10279d

[root@docker ~]# brctl show
bridge name     bridge id               STP enabled     interfaces
br-89f7bc11b602         8000.0242194d039e       no                     
br-ec761bc51778         8000.02427fa54b88       no                     
docker0         8000.02420be905a5       no              vethddb2744

[root@docker ~]# docker network inspect my_net2
.......

通过 --network 指定容器要使用的网络:

bash 复制代码
[root@docker ~]# docker run -it --network=my_net2 --name busybox2 busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
28: eth0@if29: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:16:10:02 brd ff:ff:ff:ff:ff:ff
    inet 172.22.16.2/24 brd 172.22.16.255 scope global eth0
       valid_lft forever preferred_lft forever
/ # ctrl+P,ctrl+q退出容器

[root@docker ~]# brctl show
bridge name     bridge id               STP enabled     interfaces
br-89f7bc11b602         8000.0242194d039e       no
br-ec761bc51778         8000.02427fa54b88       no      veth02dd704      
docker0         8000.02420be905a5       no              vethddb2744

通过--ip指定容器的 IP

bash 复制代码
[root@docker ~]# docker run -it --network=my_net2 --ip 172.22.16.8 --name busybox3 busybox

[root@docker ~]# brctl show
bridge name     bridge id               STP enabled     interfaces
br-89f7bc11b602         8000.0242194d039e       no                        
br-ec761bc51778         8000.02427fa54b88       no      veth02dd704       
                                                        veth5fbb7f6       
docker0         8000.02420be905a5       no              vethddb2744

注:只有使用 --subnet 创建的网络才能指定静态 IP


容器之间的连通性

同一网络中的容器、网关之间都是可以通信

busybox2 ping busybox3

bash 复制代码
[root@docker ~]# docker exec -it busybox2 sh
/ # ping -c 3 172.22.16.8
PING 172.22.16.8 (172.22.16.8): 56 data bytes
64 bytes from 172.22.16.8: seq=0 ttl=64 time=0.197 ms
64 bytes from 172.22.16.8: seq=1 ttl=64 time=0.137 ms
64 bytes from 172.22.16.8: seq=2 ttl=64 time=0.158 ms

--- 172.22.16.8 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.137/0.164/0.197 ms


# ping my_net2网关地址
/ # ping -c 3 172.22.16.1
PING 172.22.16.1 (172.22.16.1): 56 data bytes
64 bytes from 172.22.16.1: seq=0 ttl=64 time=0.149 ms
64 bytes from 172.22.16.1: seq=1 ttl=64 time=0.116 ms
64 bytes from 172.22.16.1: seq=2 ttl=64 time=0.182 ms

--- 172.22.16.1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.116/0.149/0.182 ms

通过docker network connectbusybox1 容器添加一块 my_net2的网卡

bash 复制代码
[root@docker ~]# docker network connect my_net2 busybox1

验证 busybox1 ping通 busybox2,3

bash 复制代码
[root@docker ~]# docker exec -it busybox2 sh
/ # ping -c 3 172.22.16.3
PING 172.22.16.3 (172.22.16.3): 56 data bytes
64 bytes from 172.22.16.3: seq=0 ttl=64 time=0.199 ms
64 bytes from 172.22.16.3: seq=1 ttl=64 time=0.134 ms
64 bytes from 172.22.16.3: seq=2 ttl=64 time=0.141 ms

--- 172.22.16.3 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.134/0.158/0.199 ms

容器通信的三种方式

容器之间可通过 IPDocker DNS Serverjoined 容器三种方式通信

只能在 user-defined 网络中使用 docker DNS

joined 容器 可以使两个或多个容器共享一个网络栈,共享网卡和配置信息,joined 容器之间可以通过 127.0.0.1 直接通信。

通过 --network=container:web1 指定 jointed 容器为 web1

bash 复制代码
[root@docker ~]# docker run -it --network container:web1 busybox

busybox 和 web1 的网卡 mac 地址与 IP 完全一样,它们共享了相同的网络栈;busybox 可以直接用 127.0.0.1 访问 web1 的 http 服务。

容器与外部世界

容器访问外部世界

容器默认就能访问外网

bash 复制代码
[root@docker ~]# docker run -it --name test1 busybox
/ # ping -c 3 www.baidu.com
PING www.baidu.com (223.109.82.6): 56 data bytes
64 bytes from 223.109.82.6: seq=0 ttl=127 time=21.240 ms
64 bytes from 223.109.82.6: seq=1 ttl=127 time=14.987 ms
64 bytes from 223.109.82.6: seq=2 ttl=127 time=14.651 ms

--- www.baidu.com ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 14.651/16.959/21.240 ms

注:这里外网指的是容器网络以外的网络环境,并非特指 internet

通过 NAT,docker 实现了容器对外网的访问

外部世界访问容器

docker 可将容器对外提供服务的端口映射到 host 的某个端口,外网通过该端口访问容器

通过 docker ps 或者 docker port 查看到 host 映射的端口

将 80 端口映射到 host 的 8080 端口

bash 复制代码
[root@docker ~]# docker run -d -p 8080:80 httpd
25b04cb7f6d6c012c609251a425475fcf7da03c93feb20c1d951eb45cb1ef79b
[root@docker ~]#
[root@docker ~]# curl 192.168.108.30:8080
<html><body><h1>It works!</h1></body></html>

存储

Docker 为容器提供了两种存放数据的资源:

  1. 由 storage driver 管理的镜像层和容器层
  2. Data Volume

storage driver

storage driver 实现了多层数据的堆叠并为用户提供一个单一的合并之后的统一视图

优先使用 Linux 发行版默认的 storage driver

运行docker info查看CentOS的默认 driver:

bash 复制代码
[root@docker ~]# docker info

Data Volume

Data Volume 本质上是 Docker Host 文件系统中的目录或文件,能够直接被 mount 到容器的文件系统中

特点:

  1. Data Volume 是目录或文件,而非没有格式化的磁盘(块设备)
  2. 容器可以读写 volume 中的数据
  3. volume 数据可以被永久的保存,即使使用它的容器已经销毁
bind mount

bind mount 是将 host 上已存在的目录或文件 mount 到容器

bash 复制代码
[root@docker ~]# mkdir htdocs
[root@docker ~]# cd htdocs/
[root@docker htdocs]# touch index.html
[root@docker htdocs]# vim index.html
<html><body><h1>This is a file in host file system !</h1></body></html>
[root@docker ~]# cat htdocs/index.html
<html><body><h1>This is a file in host file system !</h1></body></html>

通过 -v 将其 mount 到 httpd 容器

bash 复制代码
[root@docker ~]# docker run -d -p 80:80 -v ~/htdocs:/usr/local/apache2/htdocs httpd
883f8a22b2be796928d16ad131f6cba922492e325fdadf4275ca9f59eae5ed12
  • -v 的格式为 <host path>:<container path>

bind mount 时还可以指定数据的读写权限,默认是可读可写

bash 复制代码
# ro 设置只读权限
[root@docker ~]# docker run -d -p 80:80 -v ~/htdocs:/usr/local/apache2/htdocs:ro httpd
bf1f526ddde7a7babb29adc091eef039628ba2eb288e6db33c9ccd946cc5d5f1

[root@docker ~]# docker exec -it bf1f526ddde7 bash

root@bf1f526ddde7:/usr/local/apache2# echo "do some changes" > htdocs/index.html
bash: htdocs/index.html: Read-only file system

只 mount 文件

bash 复制代码
[root@docker ~]# docker run -d -p 80:80 -v ~/htdocs/index.html:/usr/local/apache2/htdocs/new_index.html httpd
643e8820e98a17b977a984903ddfa6f37dcae3d705d45b624d0fce5c94fecb0c
[root@docker ~]#
[root@docker ~]# curl 127.0.0.1:80
<html><body><h1>It works!</h1></body></html>
[root@docker ~]#
[root@docker ~]# curl 127.0.0.1:80/new_index.html
updated index page!
[root@docker ~]#
docker managed volume

docker managed volume 不需要指定 mount 源,只要指明 mount point

bash 复制代码
[root@docker ~]# docker run -d -p 80:80 -v /usr/local/apache2/htdocs httpd
c75f36c4bf32e39f2d078d41956be85522c0630cf91498123dcd83ba159ce873

查看容器data volume

bash 复制代码
[root@docker ~]# docker inspect c75f36c4bf32  
...
        "Mounts": [
            {
                "Type": "volume",
                "Name": "1cc915096121dea197bbbb93fc90e6491d530e0c9e2ace1de07e2a635e569d16",
                "Source": "/var/lib/docker/volumes/1cc915096121dea197bbbb93fc90e6491d530e0c9e2ace1de07e2a635e569d16/_data",
                "Destination": "/usr/local/apache2/htdocs",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
...      

Source 就是该 volume 在 host 上的目录,每当容器申请 mount docker manged volume 时,docker 都会在/var/lib/docker/volumes 下生成一个目录,这个目录就是 mount 源

除了通过 docker inspect 查看 volume,我们也可以用 docker volume 命令:

bash 复制代码
[root@docker ~]# docker volume ls
DRIVER    VOLUME NAME
local     1cc915096121dea197bbbb93fc90e6491d530e0c9e2ace1de07e2a635e569d16
[root@docker ~]#
[root@docker ~]# docker volume inspect 1cc915096121dea197bbbb93fc90e6491d530e0c9e2ace1de07e2a635e569d16
[
    {
        "CreatedAt": "2024-09-17T21:04:33+08:00",
        "Driver": "local",
        "Labels": {
            "com.docker.volume.anonymous": ""
        },
        "Mountpoint": "/var/lib/docker/volumes/1cc915096121dea197bbbb93fc90e6491d530e0c9e2ace1de07e2a635e569d16/_da
        "Name": "1cc915096121dea197bbbb93fc90e6491d530e0c9e2ace1de07e2a635e569d16",
        "Options": null,
        "Scope": "local"
    }
]

共享数据

容器与 host 共享数据

docker cp 可以在容器和 host 之间拷贝数据,也可以直接通过 Linux 的 cp 命令复制到 /var/lib/docker/volumes/xxx

bash 复制代码
[root@docker ~]# docker run -d -p 80:80 -v /usr/local/apache2/htdocs httpd
889b9d5309bd12499f8e4ee78a491d9ba7acef5660be00f30cda6569c9974c6f
[root@docker ~]# curl 127.0.0.1:80
<html><body><h1>It works!</h1></body></html>

[root@docker ~]# docker cp ~/htdocs/index.html 889b9d5309bd:/usr/local/apache2/htdocs  
Successfully copied 2.05kB to 889b9d5309bd:/usr/local/apache2/htdocs
[root@docker ~]# curl 127.0.0.1:80
updated index page!
容器之间共享数据

方法一:将共享数据放在 bind mount 中,然后将其 mount 到多个容器

方法二:使用 volume container

volume container 是专门为其他容器提供 volume 的容器

它提供的卷可以是 bind mount,也可以是 docker managed volume

bash 复制代码
[root@docker ~]# docker create --name vc_data \
 -v ~/htdocs/:/usr/local/apache2/htdocs \
 -v /other/userful/tools \
 busybox
bb4a33bf34aa7817ea752db83079aff15a5dfd77c23363f2e8dd3096d1cb910f

:这里执行的是 docker create 命令,因为 volume container 的作用只是提供数据,它本身不需要处于运行状态

容器 mount 了两个 volume:

  1. bind mount,存放 web server 的静态文件
  2. docker managed volume,存放一些实用工具

通过 --volumes-from 使用 vc_data 这个 volume container

bash 复制代码
[root@docker ~]# docker run --name web1 -d -p 80 --volumes-from vc_data httpd
362f039b562e4bf0020c38839a69bfd62733f27fda5481eb5b58178f41318ffe

volume生命周期管理

备份

所有的本地镜像都存在 host 的 /myregistry 目录中,我们要做的就是定期备份这个目录

恢复

volume 的恢复也很简单,如果数据损坏了,直接用之前备份的数据拷贝到 /myregistry 就可以了

迁移

使用更新版本的 Registry,这就涉及到数据迁移:

  1. docker stop 当前 Registry 容器。

  2. 启动新版本容器并 mount 原有 volume。

    docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:latest

当然,在启用新容器前要确保新版本的默认数据路径是否发生变化。

销毁

docker 不会销毁 bind mount,删除数据的工作只能由 host 负责。对于 docker managed volume,在执行 docker rm 删除容器时可以带上 -v 参数,docker 会将容器使用到的 volume 一并删除,但前提是没有其他容器 mount 该 volume,目的是保护数据

如果想批量删除孤儿 volume,可以执行:

docker volume rm $(docker volume ls -q)

容器监控

ps

bash 复制代码
[root@docker ~]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                                   NAMES
9f8bc2c3a5c7   nginx          "/docker-entrypoint...."   3 seconds ago    Up 2 seconds    80/tcp                                  sad_faraday
1e0b0631cf70   httpd:centos   "/bin/sh -c '/usr/sb..."   23 minutes ago   Up 23 minutes   0.0.0.0:80->80/tcp, :::80->80/tcp       myweb
4b78f371fc06   centos:ssh     "/usr/sbin/sshd -D"      32 minutes ago   Up 32 minutes   0.0.0.0:2022->22/tcp, :::2022->22/tcp   sshtest

top

bash 复制代码
[root@docker ~]# docker top sshtest    #sshtest是容器名
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                5220                5198                0                   21:31               ?                   00:00:00            /usr/sbin/sshd -D
bash 复制代码
[root@docker ~]# docker top sshtest -au
USER                PID                 %CPU                %MEM                VSZ                 RSS                 TTY                 STAT                START               TIME                COMMAND
root                5220                0.0                 0.0                 76532               7080                ?                   Ss                  21:31               0:00                /usr/sbin/sshd -D

stats

列出容器资源使用率

bash 复制代码
[root@docker ~]# docker stats
CONTAINER ID   NAME          CPU %     MEM USAGE / LIMIT     MEM %     NET I/O          BLOCK I/O         PIDS
9f8bc2c3a5c7   sad_faraday   0.00%     5.141MiB / 15.36GiB   0.03%     866B / 0B        8.19kB / 26.6kB   5
1e0b0631cf70   myweb         0.06%     38.39MiB / 15.36GiB   0.24%     1.64kB / 609B    0B / 0B           213
4b78f371fc06   sshtest       0.00%     2.258MiB / 15.36GiB   0.01%     9.7kB / 7.99kB   8.19kB / 23.6kB   1

容器日志

docker logs 命令查看容器日志

bash 复制代码
[root@docker ~]# docker logs a8286845e6f8
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.3. Set the 'ServerName' directive globally to suppress this message
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.3. Set the 'ServerName' directive globally to suppress this message
[Tue Oct 08 14:28:33.168712 2024] [mpm_event:notice] [pid 1:tid 1] AH00489: Apache/2.4.62 (Unix) configured -- resuming normal operations
[Tue Oct 08 14:28:33.168801 2024] [core:notice] [pid 1:tid 1] AH00094: Command line: 'httpd -D FOREGROUND'
.......
  • -f 参数可以继续打印出新日志

docker图形界面管理

DockerUI 容器管理器的安装与使用

简介:

DockerUI是一个易用且轻量化的 Docker 管理工具,通过 Web 界面的操作,更方便对于 Docker 指令不熟悉的用户更容易操作 Docker 。

功能:

  • Docker主机管理:数据卷管理,镜像管理,容器管理,构建管理,仓库配置管理,网络配置管理
  • Docker Swarm集群管理:集群概要信息,节点管理,Service管理,任务管理,密码管理,配置管理

安装

启动容器并映射8999端口

bash 复制代码
[root@docker ~]# docker run -d --name docker.ui --restart always -v /var/run/docker.sock:/var/run/docker.sock -p 8999:8999 joinsunsoft/docker.ui
7af59b5074732e4bd7cb9ca532379ddc35f52cbbc6aa653bda67954e56ce8d3e

Docker 图形化界面管理工具 Portainer

Portainer 是一个 Docker 图形化管理工具,可以通过 Web UI 轻松的管理容器、镜像、网络、卷

安装

创建存储卷

bash 复制代码
[root@docker ~]# docker volume create portainer_data
portainer_data

通过docker安装Portainer

bash 复制代码
[root@docker ~]# docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest
bd0967eedcae7fddbe5217bafcac7761c6a2d6f430e4b80bf5f4a9551567a828

9443 端口默认会启用 SSL,如果需要直接通过 http 访问,需要加上 -p 9000:9000 访问 9000 端口
-v /var/run/docker.sock:/var/run/docker.sock 参数使得Portainer能够访问Docker守护进程,从而能够管理容器
-v portainer_data:/data 参数则用于持久化Portainer的数据

访问

相关推荐
江湖有缘22 分钟前
Docker环境下使用RustScan端口扫描工具教程
运维·docker·容器
70asunflower28 分钟前
镜像仓库(Image Registries)详解
linux·docker·容器
青树寒鸦36 分钟前
wsl的docker备份redis和迁移
redis·docker·容器
岩屿38 分钟前
Ubuntu下安装Docker并部署.NET API(二)
运维·docker·容器·.net
hopsky1 小时前
限制 Docker Desktop 的资源使用
运维·docker·容器
春日见1 小时前
docker崩溃,闪退,与vscode断开连接
vscode·docker·容器
为什么不问问神奇的海螺呢丶1 小时前
n9e categraf k8s监控配置-n9e k8s监控看板
java·容器·kubernetes
Suchadar1 小时前
Docker搭建Web测试靶场
运维·docker·容器
Cyber4K1 小时前
【Kubernetes专项】K8s 配置管理中心 ConfigMap 实现微服务配置管理
微服务·云原生·容器·kubernetes
fleaxin2 小时前
统信服务器操作系统V20(1070)安装过程
docker·操作系统·nvidia·统信