Docker 安装
# 1. 查看机器信息,内核版本要求 3.8 以上
$ uname -a
Linux centos8 5.11.12-300.el8.aarch64 #1 SMP Fri Jul 30 12:03:15 CST 2021 aarch64 aarch64 aarch64 GNU/Linux
# 2. 关闭 selinux
$ setenforce Enforcing
$ getenforce
Enforcing
# 3. 关闭防火墙
$ systemctl stop firewalld
# 4. 检查网络,保证系统可以访问外网
$ ping baidu.com
64 bytes from 39.156.66.10 (39.156.66.10): icmp_seq=2 ttl=128 time=40.2 ms
# 5. 删除本地源
$ rm /etc/yum.repos.d/local.repo
# 6. 下载软件源配置文件
$ curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
# 7. 安装 epel 源
$ yum install epel-release -y
# 8. 安装 docker 包
$ yum list docker --show-duplicates
$ yum install -y yum-utils
$ yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
$ yum list docker-ce --show-duplicates
$ sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
# 9. 验证安装结果
$ docker version
- docker version
docker version 会输出 Docker 客户端和服务器各自的版本信息:
[hamming@centos8 ~]$ docker version
# docker 客户端信息
Client: Docker Engine - Community
Version: 20.10.18
API version: 1.41
Go version: go1.18.6
Git commit: b40c2f6
Built: Thu Sep 8 23:10:56 2022
OS/Arch: linux/arm64
Context: default
Experimental: true
# docker 引擎信息
Server: Docker Engine - Community
Engine:
Version: 20.10.18
API version: 1.41 (minimum version 1.12)
Go version: go1.18.6
Git commit: e42327a
Built: Thu Sep 8 23:09:25 2022
OS/Arch: linux/arm64
Experimental: false
containerd:
Version: 1.6.8
GitCommit: 9cd3357b7fd7218e4aec3eae239db1f68a5a6ec6
runc:
Version: 1.1.4
GitCommit: v1.1.4-0-g5fd4c4d
docker-init:
Version: 0.19.0
GitCommit: de40ad0
- docker info
docker info 会显示当前 Docker 系统相关的信息,例如 CPU、内存、容器数量、镜像数量、容器运行时、存储文件系统等等。
Client:
Context: default
Debug Mode: false
Plugins:
app: Docker App (Docker Inc., v0.9.1-beta3)
buildx: Docker Buildx (Docker Inc., v0.9.1-docker)
compose: Docker Compose (Docker Inc., v2.10.2)
Server:
Containers: 0 # 容器信息
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 20.10.18
Storage Driver: overlay2 # 存储文件系统
Backing Filesystem: xfs
Supports d_type: true
Native Overlay Diff: true
userxattr: false
Logging Driver: json-file
Cgroup Driver: systemd
Cgroup Version: 1
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: io.containerd.runtime.v1.linux runc io.containerd.runc.v2
Default Runtime: runc
Init Binary: docker-init
containerd version: 9cd3357b7fd7218e4aec3eae239db1f68a5a6ec6
runc version: v1.1.4-0-g5fd4c4d
init version: de40ad0
Security Options:
seccomp
Profile: default
Kernel Version: 5.11.12-300.el8.aarch64 # 内核
Operating System: CentOS Linux 8 # 操作系统
OSType: linux
Architecture: aarch64 # 系统架构
CPUs: 2 # 核数
Total Memory: 1.419GiB # 内存
Name: centos8
ID: MQ5W:UARY:J7LZ:QZPC:B63Z:4XW5:IUJQ:U63U:JXJD:VNGJ:7HW6:P5DD
Docker Root Dir: /data/docker
Debug Mode: false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
registry.access.redhat.com
quay.io
127.0.0.0/8
Registry Mirrors:
https://q2gr04ke.mirror.aliyuncs.com/
Live Restore Enabled: true
容器常用命令
# 查看容器,-a 参数可以查看已退出的容器
$ docker ps [-a]
# 运行容器
$ docker run hello-world # 运行简单的 docker 容器
$ docker run -d nginx:alpine # 后台运行Nginx
$ docker run -d --name red_srv redis # 后台运行 Redis
$ docker run -it --name ubuntu 2e6 sh # 使用IMAGE ID,登录 Ubuntu18.04
# 在指定容器中执行命令
$ docker exec -it red_srv sh
# 停止容器运行
$ docker stop red_srv
# 开启容器运行
$ docker start red_srv
# 删除容器
$ docker rm red_srv
# 拷贝文件
# 将 host.txt 文件拷贝到容器中的 tmp 文件夹下面
$ docker cp host.txt 062:/tmp
# 将容器内的 container.txt 文件拷贝到本机
$ docker cp 062:/tmp/container.txt ./container.txt
# 目录挂载
# 将本机目录 /tmp 挂在到容器目录 /tmp
$ docker run -d --rm -v /tmp(host):/tmp(container) redis
docker 内部角色和工作流程
docker 实际上是一个客户端 client ,它会与 Docker Engine 里的后台服务 Docker daemon 通信,而镜像存储在远端的仓库 Registry 里,客户端并不能直接访问镜像仓库。Docker client 通过 build、pull、run等命令向 Docker daemon 发送请求,而 Docker daemon 则是容器和镜像的“大管家”,负责从远端拉取镜像、在本地存储镜像,还有从镜像生成容器、管理容器等所有功能。
与虚拟机的区别
容器和虚拟机的目的都是隔离资源,保证系统安全,然后是尽量提高资源的利用率。
虚拟机创建的时候会在物理机虚拟化出一套完整的计算机硬件,在里面还能够安装任意的操作系统,这内外两个系统也同样是完全隔离,互不干扰。
而在数据中心的服务器上,虚拟机软件(即图中的 Hypervisor)同样可以把一台物理服务器虚拟成多台逻辑服务器,这些逻辑服务器彼此独立,可以按需分隔物理服务器的资源,为不同的用户所使用。
从实现的角度来看,虚拟机虚拟化出来的是硬件,需要在上面再安装一个操作系统后才能够运行应用程序,而硬件虚拟化和操作系统都比较“重”,会消耗大量的 CPU、内存、硬盘等系统资源,但这些消耗其实并没有带来什么价值,属于“重复劳动”和“无用功”,不过好处就是隔离程度非常高,每个虚拟机之间可以做到完全无干扰。
容器(即图中的 Docker),直接利用了下层的计算机硬件和操作系统,因为比虚拟机少了一层,所以自然就会节约 CPU 和内存,显得非常轻量级,能够更高效地利用硬件资源。不过,因为多个容器共用操作系统内核,应用程序的隔离程度就没有虚拟机那么高了。
运行效率是容器相比于虚拟机最大的优势,对比图中可以看到,同样的系统资源,虚拟机只能跑 3 个应用,其他的资源都用来支持虚拟机运行了,而容器则能够把这部分资源释放出来,同时运行 6 个应用。
docker 镜像的本质
从功能上来说,docker 镜像和其他安装包一样,都打包了应用程序。不同的地方在于,docker 镜像包含了程序运行的所有环境配置。使得其具有很好的跨平台便携性和兼容性,做到一次编写,到处运行。
- 镜像的内部机制
容器镜像内部并不是一个平坦的结构,而是由许多的镜像层组成,当你在执行 docker pull 命令的时候,Docker 会检查是否有从重复的层,如果本地已经存在就不会重复下载,以此节约磁盘和网络成本。
- 以 nginx:alpine 镜像为例
[hamming@centos8 ~]$ docker pull nginx:alpine
alpine: Pulling from library/nginx
9b3977197b4f: Pull complete
11e00b6b0b40: Pull complete
45812000e2a5: Pull complete
2e3e03d70957: Pull complete
bb56ce0340f0: Pull complete
a313facfd18d: Pull complete # 说明这个镜像一共有 6 层
Digest: sha256:eb05700fe7baa6890b74278e39b66b2ed1326831f9ec3ed4bdc6361a4ac2f333
Status: Downloaded newer image for nginx:alpine
docker.io/library/nginx:alpine
# 查看镜像信息
[hamming@centos8 ~]$ docker inspect nginx:alpine
Docker Hub
Docker Hub 是 Docker 公司搭建的官方 Registry 服务,和 GitHub 一样,几乎成为了容器世界的基础设施。
- 如何在 Docker Hub 上面挑选镜像
-
带有
Official image
标记的镜像,表示镜像经过了 Docker 公司的认证,有专门的团队负责审核、发布和更新,质量上绝对可以放心。 -
带有
Verified publisher
标记,是认证发行商发布的自己打包的镜像,大厂质量也值得信赖。 -
非官方镜像一种是企业官方发布上去的虽然没有经过 Docker 认证(如 openResty)但是可以放心使用,另一种就是存粹的个人上传上去的,质量上没有保证。
在选择 docker 镜像的时候,除了需要参考以上几点,下载量、星数、还有更新历史,也是选择的一个一个重要参考指标,通常可以采用随大流的方法,选择下载数最多的那个镜像。
镜像增删改查
# 拉取镜像,镜像完整名字由名字和标签组成
$ docker pull busybox:1.21-alpine
# 查看 docker 中存储的所有镜像
$ docker images
# 删除镜像
$ dcoker rmi busybox
线上上传自己的镜像
-
在 Docker Hub 上注册一个用户;
-
本机上使用 docker login 命令,用刚才注册的用户名和密码认证身份登录;
-
使用 docker tag 命令,给镜像改成带用户名的完整名字,表示镜像是属于这个用户的。或者简单一点,直接用 docker build -t 在创建镜像的时候就起好名字。
$ docker tag hello-world canghaimingue/hello-world:1.0
$ docker push canghaimingue/hello-world:1.0
离线环境保存自己的镜像
Docker 提供了 save 和 load 这两个镜像归档命令,可以把镜像导出成压缩包,或者从压缩包导入 Docker,而压缩包是非常容易保管和传输的,可以联机拷贝,FTP 共享,甚至存在 U 盘上随身携带。
# 把容器按照自己的需求个性完之后,就可以创建自己的镜像的
# docker commit 容器id 镜像名称:版本号
$ docker commit 07388cf54586 hello-world:1.0
# 保存镜像文件
#docker save 镜像名称:版本号 -o 压缩文件名称
$ docker save hello-world:1.0 -o hello_world.tar
# 加载镜像文件
$ docker load -i hello_world.tar
Docker 网络模式
Docker 有 bridge、none、host、container 四种网络模式,提供网络隔离、端口映射、容器间互通网络等各种支持。
网络模式 | 参数 | 备注 |
---|---|---|
host | --net=host | 容器和宿主机共享 network namespace。 |
container | --net= | 容器和另外一个容器共享 network namespace,K8S 中的 pod 就是多个容器共享一个 network namespace。 |
none | --net=none | 容器有独立的 network namespace,但没有对其进行任何网络设置,如分配 veth pair 和网桥连接,配置 IP 等。 |
bridge | --net=bridage | 默认为该模式,通过 -p 指定端口映射。 |
- host
连接到 host 网络的容器会共享宿主机的网络栈,容器内的网络配置与宿主机一致。直接使用host网络好处就是性能,如果容器对网络有较高要求可以直接使用host网络。但是:使用host网络也会牺牲灵活性,host已经使用的端口容器中将无法使用。
- container
创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。
$ docker run -itd --network=container:busybox --name busybox_container busybox
# 查看两个容器状态
$ docker ps | grep busybox
c0131db3ccb3 busybox "sh" 3 hours ago Up 3 hours busybox_container
1283b0f92e91 busybox "sh" 8 hours ago Up 8 hours busybox
查看两个容器的网络配置,发现他们共用的同一个 ip
- none
挂载这个网络下的容器仅有lo网络,没有其他网卡,也就不能与外界通信,适合对安全性要求较高且不需要联网的容器。如下所示
- bridge
默认网络,运行容器时如果不指定网络类型就会使用 bridge 网络。
$ docker run -itd --name busybox busybox
$ docker inspect busybox # 查看容器信息,下图可以看到网络模式 bridge
执行命令 ifconfig
可以看到网络设备中多了一个 veth7d0ac61
,这是 busybox 的虚拟网卡。
$ bridge link show | grep docker0
9: veth0f1803c@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master docker0 state forwarding priority 32 cost 2
17: veth2884210@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master docker0 state forwarding priority 32 cost 2
19: veth7d0ac61@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master docker0 state forwarding priority 32 cost 2
通过上面的命令可以看到, 这个虚拟网络设备挂在 docker0。我们再看看 busybox 内部的网络设备。
$ docker exec -it 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
18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:07:05:04 brd ff:ff:ff:ff:ff:ff
实际上, eth0@if19
和 veth7d0ac61@if18
是一对 veto pair 设备,在虚拟网络中充当着桥梁的角色,实现容器件的网络通行。
Dockerfile 的编写
关键字 | 作用 | 备注 |
---|---|---|
FROM | 指定基础镜像 | 指定 dockerfile 基于那个 image 构建 |
MAINTAINER | 作者信息 | 用来标明这个 dockerfile 谁写的 |
LABEL | 标签 | 用来标明 dockerfile 的标签 可以使用 Label 代替 Maintainer 最终都是在 docker image 基本信息中可以查看 |
RUN | 执行命令 | 执行一段命令 默认是 /bin/sh 格式: RUN command 或者 RUN ["command" , "param1","param2"] |
CMD | 容器启动命令 | 提供启动容器时候的默认命令 和 ENTRYPOINT 配合使用.格式 CMD command param1 param2 或者 CMD ["command" , "param1","param2"],只能有一个,有多个的时候最后一个生效。 |
ENTRYPOINT | 入口 | 一般在制作一些执行就关闭的容器中会使用 |
COPY | 复制文件 | build 的时候复制文件到 image 中 |
ADD | 添加文件 | build 的时候添加文件到 image 中 不仅仅局限于当前build上下文 可以来源于远程服务 |
ENV | 环境变量 | 指定 build 时候的环境变量 可以在启动的容器的时候 通过-e覆盖 格式 ENV name=value |
ARG | 构建参数 | 构建参数 只在构建的时候使用的参数 如果有ENV 那么ENV的相同名字的值始终覆盖 arg 的参数 |
VOLUME | 定义外部可以挂载的数据卷 | 指定build的image那些目录可以启动的时候挂载到文件系统中 启动容器的时候使用 -v 绑定 格式 VOLUME ["目录"] |
EXPOSE | 暴露端口 | 定义容器运行的时候监听的端口 启动容器的使用-p来绑定暴露端口 格式: EXPOSE 8080 或者 EXPOSE 8080/udp |
WORKDIR | 工作目录 | 指定容器内部的工作目录 如果没有创建则自动创建 如果指定/ 使用的是绝对地址 如果不是/开头那么是在上一条workdir的路径的相对路径 |
USER | 指定执行用户 | 指定build或者启动的时候 用户 在RUN CMD ENTRYPONT执行的时候的用户 |
HEALTHCHECK | 健康检查 | 指定监测当前容器的健康监测的命令 基本上没用 因为很多时候 应用本身有健康监测机制 |
ONBUILD | 触发器 | 当存在ONBUILD关键字的镜像作为基础镜像的时候 当执行FROM完成之后 会执行 ONBUILD的命令 但是不影响当前镜像 用处也不怎么大 |
STOPSIGNAL | 发送信号量到宿主机 | 该STOPSIGNAL指令设置将发送到容器的系统调用信号以退出。 |
SHELL | 指定执行脚本的shell | 指定RUN CMD ENTRYPOINT 执行命令的时候 使用的shell |
- Dockerfile 样例
# base image
FROM centos:7
# MAINTAINER
MAINTAINER frost <example@163.com>
# put nginx-1.12.2.tar.gz into /usr/local/src and unpack nginx
ADD nginx-1.12.2.tar.gz /usr/local/src
# install utils
RUN yum install -y gcc gcc-c++ glibc make autoconf openssl openssl-devel
RUN yum install -y libxslt-devel -y gd gd-devel GeoIP GeoIP-devel pcre pcre-devel
RUN useradd -M -s /sbin/nologin nginx
# change dir to /usr/local/src/nginx-1.12.2
WORKDIR /usr/local/src/nginx-1.12.2
# execute command to compile nginx
RUN ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx \
--with-file-aio --with-http_ssl_module --with-http_realip_module \
--with-http_addition_module --with-http_xslt_module \
--with-http_image_filter_module --with-http_geoip_module \
--with-http_sub_module --with-http_dav_module --with-http_flv_module \
--with-http_mp4_module --with-http_gunzip_module \
--with-http_gzip_static_module --with-http_auth_request_module \
--with-http_random_index_module --with-http_secure_link_module \
--with-http_degradation_module --with-http_stub_status_module
&& make && make install
ENV PATH /usr/local/nginx/sbin:$PATH
EXPOSE 80
ENTRYPOINT ["nginx"]
CMD ["-g","daemon off;"]
报错问题及解决
问题1:docker 容器修改时间 date -s 报错 date: cannot set date: Operation not permitted
# 原因:在容器中没有操作权限,在容器启动时授权即可
# 解决:
$ docker stop 5cf4eb29c8ed # 停止容器
$ docker run -itd --privileged=true -p 8080:80 nginx:latest # 重新启动,授权
问题2:更新 docker 软件失败(apt update 报错)
E: Release file for http://security.debian.org/debian-security/dists/bullseye-security/InRelease is not valid yet (invalid for another 19h 21min 31s). Updates for this repository will not be applied.
# 原因:网络和本机系统时间不一致,所以导致无法更新源
# 解决:更新一下 docker 时间即可
$ tzselect
依次选择4->9->1->1 #Asia->China-> Beijing->yes
$ sudo date -s MM/DD/YY //修改日期
$ sudo date -s hh:mm:ss //修改时间
$ sudo hwclock --systohc //修改生效
问题3:无法连接到 docker daemon
# 原因:我的是 docker 没有设置开机自启动
$ systemctl enable docker
$ systemctl start docker
$ vi /etc/docker/daemon.json # 配置参数参考官方文档
{
"graph": "/data/docker",
"storage-driver": "overlay2",
"insecure-registries": ["registry.access.redhat.com","quay.io"],
"registry-mirrors": ["https://q2gr04ke.mirror.aliyuncs.com"],
"bip": "172.7.5.1/24",
"exec-opts": ["native.cgroupdriver=systemd"],
"live-restore": true
}
# 重启docker让配置生效
$ systemctl reset-failed docker.service
$ systemctl start docker.service
$ systemctl restart docker
# 如果失败了,systemctl status docker查看报错信息
$ docker info
# 场景二:https://blog.csdn.net/m0_38088330/article/details/125343432
参考资料
-
Docker in Action
-
Kubernetes 入门实战
-
https://blog.csdn.net/weixin_41831919/article/details/102767618