回忆一下之前的创建镜像命令:
[root@node2 /]# docker run -i -t --name another_centos7 centos:7 /bin/bash
这个命令从centos7的镜像创建一个名为another_centos7的容器,并且启动bash界面
什么是Docker镜像
Docker镜像是由文件系统叠加而成的。
- 底层是引导文件系统,即bootfs
- 第二层是root文件系统,即rootfs;它是只读状态。通过联合加载技术,在root层加载了多个只读文件系统
这样的文件系统,Docker称其为镜像。镜像是可以叠加的。如下图所示:只有最顶层是可写的,其余都是只读空间
列出镜像
通过docker images命令,可以列出本地的镜像
[root@node4 ~]# sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d2c94e258dcb 11 months ago 13.3kB
centos 7 eeb6ee3f44bd 2 years ago 204MB
可以看到本地的镜像来自centos仓库。镜像文件一般保存在/var/lib/docker目录中
运行pull命令下载一个新的镜像
[root@node4 ~]# sudo docker pull centos:8
可以看到拉取结果,可以看到不同的标签TAG
[root@node4 ~]# sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d2c94e258dcb 11 months ago 13.3kB
centos 7 eeb6ee3f44bd 2 years ago 204MB
centos 8 5d0da3dc9764 2 years ago 231MB
拉取镜像
用run命令从镜像启动容器时,如果镜像不在本地,就会从官方仓库进行下载。如果没有指定标签,那么就会默认下载latest。在docker images命令后加上centos,可以只显示centos的镜像
[root@node4 ~]# docker images centos
REPOSITORY TAG IMAGE ID CREATED SIZE
centos 7 eeb6ee3f44bd 2 years ago 204MB
centos 8 5d0da3dc9764 2 years ago 231MB
指定标签拉取,前面已经运行过了
[root@node4 ~]# sudo docker pull centos:8
查找镜像
可以通过docker search命令来查找所有Docker Hub上的公开镜像
[root@node4 ~]# docker search mysql
NAME DESCRIPTION STARS OFFICIAL
mariadb MariaDB Server is a high performing open sou… 5716 [OK]
mysql MySQL is a widely used, open-source relation… 14989 [OK]
percona Percona Server is a fork of the MySQL relati… 627 [OK]
phpmyadmin phpMyAdmin - A web interface for MySQL and M… 964 [OK]
查找结果包含如下列:
仓库名、镜像描述、用户评价:也就是星星数、是否官方
构建镜像
创建和管理自己的镜像,有2种方式
- 使用docker commit命令
- 使用docker build命令和Dockerfile文件
目前主流是使用第二种方式,不过第一种也会进行介绍
注册Docker Hub账号
https://hub.docker.com/
注册过程略。现在可以直接通过github或者Google账号注册,还挺方便的。如果是直接用Github或者google账号注册的,需要设置下密码,等会登录会用到。
然后使用docker login命令登录:
[root@node4 ~]# sudo docker login
Log in with your Docker ID or email address to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com/ to create one.
You can log in with your password or a Personal Access Token (PAT). Using a limited-scope PAT grants better security and is required for organizations using SSO. Learn more at https://docs.docker.com/go/access-tokens/
Username: kayotin
Password:
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
可以使用docker logout来退出登录。
用Docker的commit命令创建镜像
使用docker commit命令,就和我们修改代码提交一样。
首先新建一个容器
[root@node4 ~]# docker run -i -t centos:7 /bin/bash
试着安装一个apache
[root@69af1d3b05c2 ~]# yum install httpd
然后执行exit退出,继续运行commit命令,将该容器保存到镜像(容器id可以通过docker ps -a查看
[root@node4 ~]# docker commit 69af1d3b05c2 kayotin/apachetest
sha256:7b2dde3fde6ed893914216d5693e305c7bdc47934879a3f0c4da5cc0e5fe27a8
可以通过docker images查看该镜像
[root@node4 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
kayotin/apachetest latest 7b2dde3fde6e 18 minutes ago 885MB
我们可以通过更多一些参数,输入更多commit信息。
# -m 指定commit信息 -a指定作者信息 最后:指定了标签
[root@node4 ~]# docker commit -m"commit message" -a"hanayo" 2cdeb9fa7543 kayotin/apache2:server
我们可以通过run命令,从镜像启动容器
[root@node4 ~]# docker run -t -i kayotin/apache2:server
用Dockerfile创建镜像
首先我们新建一个目录,创建一个叫Dockerfile的空文件
[root@node4 ~]# mkdir kayotin_repo
[root@node4 ~]# cd kayotin_repo/
[root@node4 kayotin_repo]# ls
[root@node4 kayotin_repo]# touch Dockerfile
[root@node4 kayotin_repo]# ls
Dockerfile
这个目录就是我们的构建环境,Docker称此环境为上下文或者构建上下文build context。
我们用vim编辑该Dockerfile文件,内容如下
# 基础镜像
FROM centos:7
# 作者信息
MAINTAINER Kayotin "hanayo@kayotin.cn"
# 安装Nginx
RUN yum -y install epel-release && \
yum -y update && \
yum -y install nginx
# 修改nginx 默认页
COPY index.html /usr/share/nginx/html/index.html
# 开放端口80
EXPOSE 80
其中上面的index.html内容如下,注意一定要在head中指定字符集是utf-8,否则中文会乱码
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
</head>
<body>
hello, I am hanayo.
你好,我是花阳亲。
</body>
</html>
创建Dockerfile文件后,还可以指定.dockerignore
文件(可选),它表示哪些文件不希望被打包进image。
.git
venu
接下来,使用build命令构建镜像, -t参数指定了镜像的仓库和名称,也可以在后面加:指定版本,默认是latest,例如:docker build -t=“kayotin01/demo01:1.01” .
[root@node4 kayotin_repo]# docker build -t="kayotin01/demo01" .
[+] Building 78.0s (6/6) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 288B 0.0s
=> [internal] load metadata for docker.io/library/centos:7 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> CACHED [1/2] FROM docker.io/library/centos:7 0.0s
=> [2/2] RUN yum -y install epel-release && yum -y update && yum -y install nginx 73.5s
=> exporting to image 4.3s
=> => exporting layers 4.2s
=> => writing image sha256:7305f86bc0d28253df007343fc302c375d434602fef502b5ceaf118a98a71ba5 0.0s
=> => naming to docker.io/kayotin01/demo01 0.0s
[root@node4 kayotin_repo]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
kayotin01/demo01 latest 7305f86bc0d2 About a minute ago 659MB
注意,这个命令最后有一个点,也就是指定Dockerfile在当前目录。也可以指定一个git仓库:
docker build -t="kayotin01/demo01" git@github.com:kayotin/dockerfile
或者用-f参数指定Dockerfile的位置
docker build -t="kayotin01/demo01" -f 文件路径
Dockerfile和构建缓存
如果镜像构建失败,会显示在哪一步失败,例如
=> CACHED [1/3] FROM docker.io/library/centos:7 0.0s
=> ERROR [2/3] RUN yum install -y nginx 16.3s
------
> [2/3] RUN yum install -y nginx:
如果修改了命令继续构建镜像,其实会从上一步成功的缓存开始构建;如果希望从头开始而不使用上一步的缓存,可以使用--no-cahe
参数
docker build --no-cache -t="kayotin01/demo01" .
从新镜像启动容器
现在已经可以看到我们刚构建的镜像了
[root@node4 kayotin_repo]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
kayotin01/demo01 latest 7305f86bc0d2 24 minutes ago 659MB
使用docker history命令可以看到该镜像的构建过程
[root@node4 kayotin_repo]# docker history 7305f86bc0d2
IMAGE CREATED CREATED BY SIZE COMMENT
7305f86bc0d2 25 minutes ago EXPOSE map[80/tcp:{}] 0B buildkit.dockerfile.v0
<missing> 25 minutes ago RUN /bin/sh -c yum -y install epel-release &… 455MB buildkit.dockerfile.v0
<missing> 25 minutes ago MAINTAINER Kayotin "hanayo@kayotin.cn" 0B buildkit.dockerfile.v0
<missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 2 years ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
我们使用以下命令从新镜像启动容器
# -d 后台运行 -p 指定端口
[root@node4 kayotin_repo]# docker run -d -p 80 --name my_demo kayotin01/demo01 nginx -g "daemon off;"
f75d2fc4d6fc4ea7125796f368f228555ae3ad7b6d29b310c35b1132137a18e1
如果在-p参数中不指定的话,docker会在宿主主机随机指定一个32768-61000的端口来指向这个端口,可以通过docker ps -l 看到这个端口,也可以通过docker port命令查看
[root@node4 kayotin_repo]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f75d2fc4d6fc kayotin01/demo01 "nginx -g 'daemon of…" 2 minutes ago Up 2 minutes 0.0.0.0:32768->80/tcp, :::32768->80/tcp my_demo
[root@node4 kayotin_repo]# docker port my_demo 80
0.0.0.0:32768
[::]:32768
如果指定的话可以如下这样写:
docker run -d -p 80:80 \
--name my_demo kayotin01/demo01 nginx -g "daemon off;"
# 指定特定网络
docker run -d -p 127.0.0.1:80:80 --name my_demo kayotin01/demo01 nginx -g "daemon off;"
我们通过本地浏览器访问,得到如下画面
至此我们就得到了一个简单的静态nginx代理。
Dockerfile的其他指令
Dockerfile里还有一些很有用的指令,这里简单介绍下
- CMD:指定一个容器启动时要运行的命令。会被run命令指定的命令覆盖
- WORDDIR:指定工作目录
- ENV:设置环境变量
- USER:指定运行该镜像的用户
- COPY:将本地文件复制到镜像中 COPY 本地文件路径 容器中文件路径,如果容器中的路径不存在,会自动创建路径
将镜像推送到Docker Hub
可以使用push命令将镜像推送上传到Docker Hub
首先需要在docker hub上创建账号和登录,这个前面讲过了。
然后通过以下语句上传,如果仓库存在,会上传到对应仓库,否则会新建一个仓库
docker push 用户名/仓库名:tagname
例如上面的镜像,先修改个名字
docker tag kayoitn01/mydemo01 kayotin/mydemo:1.01
那么上传命令就是:
[root@node4 kayotin_repo]# docker push kayotin/demo01:1.01
最终上传成功如下所示,上传到了kayotin账户下的demo01仓库
删除镜像
使用docker rmi + 镜像名称命令删除镜像
# 如果有容器在使用这个镜像,会报如下的错误
[root@node4 ~]# docker rmi kayotin/apache2:server
Error response from daemon: conflict: unable to remove repository reference "kayotin/apache2:server" (must force) - container 6d00a319a9e8 is using its referenced image 8ce4bf297625
如果有容器使用镜像,需要先删除容器,然后执行删除
# 可以看到删除是一层一层执行的
[root@node4 ~]# docker rmi kayotin/apache2:server
Untagged: kayotin/apache2:server
Deleted: sha256:8ce4bf297625ff3693db4e89acb515824f27b391f2e4b3e7e8784beb2fce4cb0
Deleted: sha256:06d5068d22b6af1ad81c235a57579125c1770b4e030c376c7eebd1ba57a57e58
此操作只会删除本地的镜像,如果需要删除docker hub上的仓库,需要在网页上点击settings中的Delete Repository按钮:
顺便,运行以下命令可以删除本地所有镜像。
[root@node4 ~]# docker rmi `docker images -a -q`
我们已经删除了本地的镜像和所有容器,然后再复习下从我们上传的镜像启动容器
[root@node4 ~]# docker run kayotin/mydemo:1.02
Unable to find image 'kayotin/mydemo:1.02' locally
1.02: Pulling from kayotin/mydemo
c1ec31eb5944: Pull complete
Digest: sha256:d37ada95d47ad12224c205a938129df7a3e52345828b4fa27b03a98825d1e2e7
Status: Downloaded newer image for kayotin/mydemo:1.02
Hello from Docker!
......
运行自己的Docker Registry
默认发布到docker hub上的仓库是公共的,如果想要该仓库只对自己可见,有2个选择。
- 利用docker hub上的私有仓库(这是付费服务
- 搭建自己的本地仓库
显然我们使用第二种,运行如下命令,从官方的registry镜像启动容器
[root@node4 ~]# docker run -p 5000:5000 registry
Unable to find image 'registry:latest' locally
latest: Pulling from library/registry
619be1103602: Pull complete
......
启动后,访问http://192.168.32.14:5000/v2/,得到{}
说明运行正常。此时可以按ctrl+c退出。正常情况我们应该加上-d来用守护进程启动:
docker run -d -p 5000:5000 registry
使用自己搭建的docker仓库
首先我们pull一个nginx的官方镜像
[root@node4 ~]# docker pull nginx:1.24
1.24: Pulling from library/nginx
04e7578caeaa: Pull complete
用tag命令改个名字,改为我们本地仓库的名称
[root@node4 ~]# docker tag nginx:1.24 192.168.32.14:5000/test_nginx:1.24
然后运行以下命令进行push
[root@node4 ~]# docker push 192.168.32.14:5000/test_nginx:1.24
解决http推送报错问题
在推送到的时候报错误,默认是使用 https
提交,这个搭建的默认使用的是 http
,解决方法两个:
- 创建一个
https
映射 - 将仓库地址加入到不安全的仓库列表中
我们使用第二种方法,加入到不安全的仓库列表中,修改docker配置文件 vim etc/docker/daemon.json
添加 insecure-registries
配置信息,如果 daemon.json 文件不存在可以创建,关键配置项,将仓库将入到不安全的仓库列表中。
{
"insecure-registries":[
"192.168.32.14:5000"
]
}
重启服务 service docker restart
,
还需要关闭 SELinux
强制访问控制安全系统,通过下面方法禁用 SELinux 之后就可以 push 了
[root@node4 ~]# docker push 192.168.32.14:5000/test_nginx:1.24
The push refers to repository [192.168.32.14:5000/test_nginx]
bc4a3582faa9: Pushed
...
查看和使用本地仓库的镜像
访问http://192.168.32.14:5000/v2/test_nginx/tags/list,可以看到如下信息
{"name":"test_nginx","tags":["1.24"]}
访问http://192.168.32.14:5000/v2/_catalog,可以看到
{"repositories":["test_nginx"]}
我们把本地的镜像删除,然后试着从本地仓库拉取镜像
# 删除本地镜像
[root@node4 ~]# docker rmi nginx:1.24
Untagged: nginx:1.24
Untagged: nginx@sha256:e56797eab4a5300158cc015296229e13a390f82bfc88803f45b08912fd5e3348
[root@node4 ~]# docker rmi 6c0218f16876
Untagged: 192.168.32.14:5000/test_nginx:1.24
......
从本地仓库拉取镜像
[root@node4 ~]# docker pull 192.168.32.14:5000/test_nginx:1.24
1.24: Pulling from test_nginx
04e7578caeaa: Pull complete
......
小结
本次我们学些了如下内容:
- 如何查找和使用公共镜像
- 如何通过commit和Dockerfile两种方式来创建自己的镜像
- 如何将自己的镜像上传到docker hub
- 如何创建本地的私人docker仓库