一、docker镜像
docker镜像管理
镜像管理
镜像,即创建容器的模版,含有启动容器所需要的文件系统及所需要的内容,因此镜像主要用于方便和快速的创建并启动容器
Docker 镜像说明:Docker 镜像中有没有内核
从镜像大小上面来说,一个比较小的镜像只有1KB多点,或几MB,而内核文件需要几十MB, 因此镜像里面是没有内核的,镜像在被启动为容器后将直接使用宿主机的内核,而镜像本身则只提供相应的rootfs,即系统正常运行所必须的用户空间的文件系统,比如/dev/,/proc,/bin,/etc等目录,所以容器当中基本是没有/boot目录的,而/boot当中保存的就是与内核相关的文件和目录。
为什么没有内核?
由于容器启动和运行过程中是直接使用了宿主机的内核,不会直接调用过物理硬件,所以也不会涉及到硬件驱动,因此也用不上内核和驱动。而如果虚拟机技术,对应每个虚拟机都有自已独立的内核
容器中的程序后台运行,会导致此容器启动后立即退出?
Docker容器如果希望启动后能持续运行,就必须有一个能前台持续运行的进程,如果在容器中启动传统的服务,如:httpd,php-fpm等均为后台进程模式运行,就导致 docker 前台没有运行的应用,这样的容器启动后,会立即自杀。所以一般会将服务程序以前台方式运行,对于有一些可能不知道怎么前台运行的程序,只需要在你启动的命令之后添加类似于 tail ,top 这种可以前台运行的程序,常用的方法,如:tail -f /etc/hosts
docker镜像生命周期
通过容器手动制作docker镜像
Docker 镜像制作类似于虚拟机的镜像(模版)制作,即按照公司的实际业务务求将需要安装的软件、相关配置等基础环境配置完成,然后将其做成镜像,最后再批量从镜像批量生产实例,这样可以极大的简化相同环境的部署工作,Docker的镜像制作分为手动制作(基于容器)和自动制作(基于DockerFile),企业通常都是基于Dockerfile制作镜像
基于容器手动制作镜像步骤
基于容器手动制作镜像步骤具体如下:
- 下载一个基础的官方镜像,如:centos 或ubuntu
- 基于基础镜像启动一个容器,并进入到容器
- 在容器里面做配置操作
- 安装基础命令
- 配置运行环境
- 安装服务和配置服务
- 放程序代码
- 提交为一个新镜像,docker commit
- 基于自己的的镜像创建容器并测试访问
docker镜像相关操作
搜索镜像
可以官方网站进行镜像的搜索 http://hub.docker.com
可以执行docker search命令进行搜索
Usage: docker search [OPTIONS] TERM
说明:
OFFICIAL:官方
AUTOMATED:使用第三方docker服务来帮助编译镜像,可以在互联网上面直接拉取到镜像,减少了繁琐的编译过程
##查找镜像
root@user:~# docker search centos
##选择性的查找镜像
root@user:~# docker search --filter=stars=30 centos
下载镜像
从docker 仓库将镜像下载到本地,命令格式如下:
docker pull 仓库服务器:端口/项目名称/镜像名称:tag(版本)号
镜像下载保存的路径:
/var/lib/docker/overlay2/镜像ID
docker pull hello-world
docker pull alpine
docker pull busybox
docker pull nginx
docker pull centos
docker pull centos:centos7.7.1908
docker pull docker.io/library/mysql:5.7.29
docker pull mysql:5.6.47
docker 镜像加速配置
docker 镜像官方的下载站点是:https://hub.docker.com/
从国内下载官方的镜像站点有时候会很慢,因此可以更改docker配置文件添加一个加速器,可以通过加速器达到加速下载镜像的目的
国内有许多公司都提供了docker 加速镜像,比如:阿里云,腾讯云,网易云,
配置镜像加速器
修改daemon配置文件/etc/docker/daemon.json来使用加速器
mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://si7y70hh.mirror.aliyuncs.com"]
}
EOF
#网易云:http://hub-mirror.c.163.com/
#腾讯云:https://mirror.ccs.tencentyun.com
systemctl daemon-reload
systemctl restart docker
##配置示例
root@user:~# cat /etc/docker/daemon.json
{
"registry-mirrors": ["https://pb06wc6t.mirror.aliyuncs.com"]
}
root@user:~# docker info | tail
Debug Mode: false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
127.0.0.0/8
Registry Mirrors:
https://pb06wc6t.mirror.aliyuncs.com/
Live Restore Enabled: false
查看本地镜像
docker images 可以查看下载至本地的镜像
docker images [OPTIONS] [REPOSITORY[:TAG]]
常用选项:
-q, --quiet Only show numeric IDs
-a, --all Show all images (default hides intermediate images)
--digests Show digests
--no-trunc Don't truncate output
执行结果的显示信息说明:
REPOSITORY #镜像所属的仓库名称
TAG #镜像版本号(标识符),默认为latest
IMAGE ID #镜像唯一ID标示
CREATED #镜像创建时间
VIRTUAL SIZE #镜像的大小
root@user:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest c316d5a335a5 2 weeks ago 142MB
busybox latest beae173ccac6 6 weeks ago 1.24MB
alpine latest c059bfaa849c 2 months ago 5.59MB
hello-world latest feb5d9fea6a5 4 months ago 13.3kB
root@user:~# docker images -q
c316d5a335a5
beae173ccac6
c059bfaa849c
feb5d9fea6a5
root@user:~# docker inspect alpine
镜像导出
利用docker save命令可以将从本地镜像导出问为一个压缩文件,然后复制到其他服务器进行导入使用。
docker save [OPTIONS] IMAGE [IMAGE...]
选项:
-o, --output string Write to a file, instead of STDOUT
常见用法:
docker save IMAGE -o /path/file.tar.gz
docker save IMAGE > /path/file.tar.gz
root@user:~# docker save alpine > alpine.tar.gz
root@user:~# docker save mysql:5.7.29 -o mysql5.7.29.tar.gz
root@user:~# ls -lrt
total 455524
-rw-r--r-- 1 root root 5875712 Feb 13 08:12 alpine.tar.gz
-rw------- 1 root root 460571648 Feb 13 08:30 mysql5.7.29.tar.gz
镜像导入
利用docker load命令可以将镜像导出的压缩文件再导入
docker load [OPTIONS]
选项
-i, --input string Read from tar archive file, instead of STDIN
-q, --quiet Suppress the load output
[root@node2 ~]# docker load -i alpine.tar.gz
8d3ac3489996: Loading layer 5.866MB/5.866MB
Loaded image: alpine:latest
[root@node2 ~]# docker load < mysql5.7.29.tar.gz
删除镜像
docker rmi 命令可以删除本地镜像
docker rmi [OPTIONS] IMAGE [IMAGE...]
选项:
-f, --force Force removal of the image
--no-prune Do not delete untagged parents
root@user:~# docker rmi mysql:5.7.29
root@user:~# docker rmi beae173ccac6
##强制删除正在使用的镜像,也会删除对应的容器
[root@ubuntu1804 ~]#docker rmi -f centos:centos8.1.1911
##删除所有镜像
[root@node4 ~]# docker rmi `docker images -q`
命令总结:
docker search centos
docker pull alpine
docker images
docker save > /opt/centos.tar #centos #导出镜像
docker load -i centos-latest.tar.xz #导入本地镜像
docker rmi 镜像ID/镜像名称 #删除指定ID的镜像,此镜像对应容器正启动镜像不能被删除,除非将容器全部关闭
二、docker容器
容器生命周期
容器操作命令
启动容器
docker run 可以启动容器,进入到容器,并随机生成容器ID和名称
docker run [选项] [镜像名] [shell命令] [参数]
选项:
-i, --interactive Keep STDIN open even if not attached,通常和-t一起使用
-t, --tty Allocate a pseudo-TTY,通常和-i一起使用
-d, --detach Run container in background and print container ID,台后运行,默认前台
--name string Assign a name to the container 为容器指定一个名称,注意每个容器的名称要唯一
--rm Automatically remove the container when it exits 容器运行终止即自行删除
-p, --publish list Publish a container's port(s) to the host
-P, --publish-all Publish all exposed ports to random ports
--dns list Set custom DNS servers
--entrypoint string Overwrite the default ENTRYPOINT of the image
--restart policy
--privileged Give extended privileges to container
root@user:~# docker run -it busybox sh
/ # exit
#启动的容器在执行完shel命令就退出,用于测试
root@user:~# docker run busybox /bin/echo "hello world"
hello world
#指定容器名称,注意每个容器的名称要唯一
root@user:~# docker run --name alpine1 alpine
#创建容器后直接进入,执行exit退出后容器关闭
root@user:~# docker run -it --name alpine2 alpine
/ # cat /etc/issue
Welcome to Alpine Linux 3.15
Kernel \r on an \m (\l)
/ # exit
#后台启动容器
root@user:~# docker run -d --name alpine4 alpine
#一次性运行容器,退出后立即删除,用于测试
root@user:~# docker run -it --rm alpine cat /etc/issue
Welcome to Alpine Linux 3.15
Kernel \r on an \m (\l)
#开机自动运行容器
#默认容器不会自动启动,设置容器总是运行
root@user:~# docker run -d --name nginx --restart=always -p 80:80 nginx
显示容器
docker ps 可以显示当前存在容器
#显示运行的容器
root@user:~# docker ps
#显示全部容器,包括退出状态的容器
root@user:~# docker ps -a
#只显示容器ID
root@user:~# docker ps -qa
#显示容器大小
root@user:~# docker ps -as
#显示指定的容器
root@user:~# docker ps -f 'status=exited'
查看容器内的进程
docker top CONTAINER [ps OPTIONS]
root@user:~# docker run -d --name httpd httpd
root@user:~# docker top httpd
root@user:~# docker run -d alpine /bin/sh -c 'i=1;while true;do echo helloi;let i++;sleep 1;done'
c161e66e29f02255ac54912fe6eed4f5ff141403ad033806f1551f8d1b6cc778
root@user:~# docker top c161
查看容器的详细信息
docker inspect [OPTIONS] NAME|ID [NAME|ID...]
Options:
-f, --format string Format the output using the given Go template
-s, --size Display total file sizes if the type is container
root@user:~# docker inspect c161
删除容器
docker rm 可以删除容器,即使容正在运行当中,也可以被强制删除掉
docker rm [OPTIONS] CONTAINER [CONTAINER...]
选项:
-f, --force Force the removal of a running container (uses SIGKILL)
-v, --volumes Remove the volumes associated with the container
docker ps -a
docker rm httpd
docker rm -f httpd
##删除所有容器
docker rm -f `docker ps -qa`
##删除指定状态的容器
root@user:~# docker rm `docker ps -qf status=exited`
容器端口映射
docker run -p 可以将容器的预定义的指定端口映射到宿主机的相应端口
-p <containerPort>:将指定的容器端口映射至主机所有地址的一个动态端口
-p <hostPort>:<containerPort>:将容器端口<containerPort>映射至指定的主机端口<hostPort>
-p <ip>::<containerPort>:将指定的容器端口<containerPort>映射至主机指定<ip>的动态端口
-p <ip>:<hostPort>:<containerPort>:将指定的容器端口<containerPort>映射至主机指定<ip>的端口<hostPort>
查看容器已经映射的端口
docker port 可以查看容器的端口映射关系
注意:多个容器映射到宿主机的端口不能冲突,但容器内使用的端口可以相同
查看容器日志
docker logs 可以查看容器的日志
docker logs [OPTIONS] CONTAINER
#查看一次
root@user:~# docker logs nginx
#持续查看
root@user:~# docker logs -f nginx
进入容器方法
使用exec命令,可以执行单次命令,以及进入容器,测试环境使用此方式,虽然exit退出容器还在运行,此为推荐方式
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
常用选项:
-d, --detach Detached mode: run command in the background
-e, --env list Set environment variables
-i, --interactive Keep STDIN open even if not attached
-t, --tty Allocate a pseudo-TTY
常见用法
docker exec -it 容器ID bash|sh
镜像仓库registry
统一保存镜像而且是多个不同镜像版本的地方,叫做镜像仓库
- Docker hub:docker官方的公共仓库,已经保存了大量的常用镜像,可以方便大家直接使
- 阿里云,网易等第三方镜像仓库
- Image registry:docker 官方提供的私有仓库部署工具,无web管理界面,目前使用较少
- Harbor:vmware 提供的自带web界面自带认证功能的镜像仓库,目前有很多公司使用
#镜像地址格式
172.18.200.101/project/centos:7.2.1511
172.18.200.101/project/centos: latest
172.18.200.101/project/java-7.0.59:v1
172.18.200.101/project/java-7.0.59:v2
三、docker安装
Ubuntu14.04/16.04/18.04安装docker
##安装依赖
apt install apt-transport-https ca-certificates curl gnupg2 software-properties-common -y
##信任docker的GPG公钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
##添加软件仓库
add-apt-repository \
"deb [arch=amd64] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu \
$(lsb_release -cs) \
stable"
##更新并安装docker-ce
apt update
apt install -y docker-ce
##安装指定版本的docker-ce
root@user:~# apt-cache madison docker-ce
##安装指定版本的docker-ce: (VERSION例如上面的18.06.0~ce~3-0~ubuntu)
apt-get -y install docker-ce=[VERSION] docker-ce-cli=[VERSION]
##删除docker-ce
apt purge docker-ce
rm -rf /var/lib/docker
Centos安装docker
下载rpm包安装
官方rpm包下载地址:Index of linux/centos/7/x86_64/stable/Packages/
阿里镜像下载地址:
阿里云开源镜像站资源目录
通过yum源安装
由于官网的yum源太慢,下面使用阿里云的Yum源进行安装
# step 1: 安装必要的一些系统工具
yum install -y yum-utils device-mapper-persistent-data lvm2
# Step 2: 添加软件源信息
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# Step 3: 更新并安装Docker-CE
yum makecache fast
yum -y install docker-ce
# Step 4: 开启Docker服务
systemctl start docker
#验证docker版本
# docker version
Client: Docker Engine - Community
Version: 20.10.12
API version: 1.41
Go version: go1.16.12
Git commit: e91ed57
Built: Mon Dec 13 11:45:27 2021
OS/Arch: linux/amd64
Context: default
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 20.10.12
API version: 1.41 (minimum version 1.12)
Go version: go1.16.12
Git commit: 459d0df
Built: Mon Dec 13 11:43:36 2021
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.4.12
GitCommit: 7b11cfaabd73bb80907dd23182b9347b4245eb5d
runc:
Version: 1.0.2
GitCommit: v1.0.2-0-g52b36a2
docker-init:
Version: 0.19.0
GitCommit: de40ad0
#验证docker0网卡,在docker安装启动之后,默认会生成一个名称为docker0的网卡并且默认IP地址为172.17.0.1的网卡
# ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:2b:ba:84:2d txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.20.21.80 netmask 255.255.0.0 broadcast 172.20.255.255
inet6 fe80::20c:29ff:fe58:5c36 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:58:5c:36 txqueuelen 1000 (Ethernet)
RX packets 2648 bytes 217209 (212.1 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2385 bytes 255866 (249.8 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
四、制作nginx镜像
Dockerfile 制作基于centos基础镜像的nginx镜像
# cd /data/dockerfile/system/centos
# cat Dockerfile
FROM centos:centos7.9.2009
RUN /usr/bin/rm -f /etc/yum.repos.d/CentOS-Base.repo \
&& /usr/bin/curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
&& /usr/bin/curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
&& /usr/bin/yum install -y gcc make gcc-c++ glibc glibc-devel pcre pcre-devel openssl openssl-devel systemd-devel zlib-devel \
&& /usr/bin/yum clean all \
&& /usr/bin/rm -f /etc/localtime \
&& /usr/bin/ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# cat build.sh
#!/bin/bash
docker build -t centos7-base:v1 .
# chmod +x build.sh
# ./build.sh
# cd /data/dockerfile/web/nginx/1.18/
# cat nginx.conf
user nginx;
worker_processes auto;
daemon off; #增加此行,前台运行nginx
error_log logs/error.log error;
pid logs/nginx.pid;
events {
worker_connections 10240;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
gzip on;
server {
listen 80;
server_name localhost;
charset koi8-r;
location / {
root html;
index index.html index.htm;
}
}
}
# wget http://nginx.org/download/nginx-1.18.0.tar.gz
# mkdir app/
# echo "Test Page in app" > app/index.html
# tar zcf app.tar.gz app
# ls
app app.tar.gz nginx-1.18.0.tar.gz nginx.conf
# cat Dockerfile
FROM centos7-base:v1
LABEL maintainer="Ilinux <root@ilinux.com>"
ENV NGX_ROOT="/usr/local/nginx"
ADD nginx-1.18.0.tar.gz /usr/local/src
RUN cd /usr/local/src/nginx-1.18.0 \
&& ./configure --prefix=${NGX_ROOT} --with-http_stub_status_module --with-http_ssl_module --with-http_gzip_static_module \
&& /usr/bin/make -j4 \
&& /usr/bin/make install \
&& /usr/bin/rm -rf /usr/local/src/nginx-1.18.0 \
&& /usr/sbin/useradd -s /sbin/nologin nginx
COPY nginx.conf ${NGX_ROOT}/conf
ADD app.tar.gz ${NGX_ROOT}/html
EXPOSE 80 433
CMD ["/usr/local/nginx/sbin/nginx"]
# cat build.sh
#!/bin/bash
#
docker build -t nginx-centos:1.18.0 .
# chmod +x build.sh
# ./build.sh
# docker run -it --rm -p 80:80 nginx-centos:1.18.0
# curl 127.0.0.1/app/
Test Page in app
五、镜像分层
镜像含里面是一层层的文件系统,叫做 Union FS(联合文件系统),联合文件系统,可以将几层目录挂载到一起(就像千层饼,洋葱头,俄罗斯套娃一样),形成一个虚拟文件系统,虚拟文件系统的目录结构就像普通 linux 的目录结构一样,镜像通过这些文件再加上宿主机的内核共同提供了一个 linux 的虚拟环境,每一层文件系统叫做一层 layer,联合文件系统可以对每一层文件系统设置三种权限,只读(readonly)、读写(readwrite)和写出(whiteout-able),但是镜像中每一层文件系统都是只读的,构建镜像的时候,从一个最基本的操作系统开始,每个构建提交的操作都相当于做一层的修改,增加了一层文件系统,一层层往上叠加,上层的修改会覆盖底层该位置的可见性,这也很容易理解,就像上层把底层遮住了一样,当使用镜像的时候,我们只会看到一个完全的整体,不知道里面有几层也不需要知道里面有几层,结构如下:
一个典型的 Linux文件系统由bootfs和rootfs两部分组成,bootfs(boot file system) 主要包含bootloader和kernel,bootloader主要用于引导加载 kernel,当 kernel 被加载到内存中后bootfs会被umount 掉,rootfs (root file system) 包含的就是典型 Linux 系统中的/dev,/proc,/bin,/etc 等标准目录和文件,下图就是镜像中最基础的两层结构,不同的 linux 发行版(如 ubuntu 和 CentOS ) 在 rootfs 这一层会有所区别。
容器、镜像父镜像:
Docker容器的分层
容器的数据分层
LowerDir:image 镜像层(镜像本身,只读)
UpperDir:容器的上层(读写)
MergedDir:容器的文件系统,使用Union FS(联合文件系统)将lowerdir 和upperdir 合并给容器使用
WorkDir:容器在 宿主机的工作目录
Docker 数据管理
如果将正在运行中的容器修改生成了新的数据,或者修改了现有的一个已经存在的文件内容,那么新产生的数据将会被复制到读写层,进行持久化保存,这个读写层也就是容器的工作目录,此即“写时复制(COW) copy on write”机制。
如下图是将对根的数据写入到了容器的可写层,但是把/data 中的数据写入到了一个另外的volume 中用于数据持久化
六、docker私有云单机仓库Docker Registry
搭建本地docker registry镜像仓库
官方文档地址:https://docs.docker.com/registry/
官方github 地址:https://github.com/docker/distribution
官方部署文档:https://github.com/docker/docker.github.io/blob/master/registry/deploying.md
#下载docker registry镜像
# docker pull registry:2.6.2
#创建授权用户密码使用目录
# mkdir /docker/auth -p
#创建用户
# docker run --entrypoint htpasswd registry:2.6.2 -Bbn test 123456 > auth/htpasswd
#创建授权的registry用户
# cat auth/htpasswd
test:$2y$05$kp2VB47pXJorbo0ZB6s6ce0oo9eUYnfQ0OAqBv5S0g8qbKMamO6XO
#启动docker registry 容器
# docker run -d -p 5000:5000 --restart=always --name registry -v /docker/auth:/auth -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd registry:2.6.2
#将registry仓库服务器地址加入service 单元文件,否则直接登入会报错
# vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 172.20.22.26:5000
# systemctl daemon-reload
# systemctl restart docker
# docker login 172.20.22.26:5000
#打标签并上传镜像
# docker tag alpine:latest 172.20.22.26:5000/alpine:latest
# docker push 172.20.22.26:5000/alpine:latest
#在另一台主机上下载镜像测试,先修改docker的service 文件
# vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 172.20.22.26:5000
# systemctl daemon-reload
# systemctl restart docker
# docker login 172.20.22.26:5000
# docker pull 172.20.22.26:5000/alpine:latest
# docker run -it --rm 172.20.22.26:5000/alpine:latest
/ # cat /etc/issue
Welcome to Alpine Linux 3.15
Kernel \r on an \m (\l)
/ # exit