Docker从入门到实战-深入探讨Image
说白了,image就是由一层一层的layer组成的。
Image常见操作
(1)查看本地image列表
docker images
docker image ls
(2) 获取远端镜像
docker pull
(3) 删除镜像[注意此镜像如果正在使用,或者有关联的镜像,则需要先处理完]
docker image rm imageid
docker rmi -f imageid 强制删除镜像
docker rmi -f $(docker image ls) 删除所有镜像
(4)运行镜像
docker run image
(5) 发布镜像
docker push
官方Image
https://github.com/docker-library
官方镜像制作的Dockerfile
https://github.com/docker-library/official-images/tree/master/library
Dockerfile镜像制作
指令说明
FROM
定制的镜像都是基于 FROM 的镜像,这里的 java:8 就是定制需要的基础镜像。
VOLUME
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
作用:
- 避免重要的数据,因容器重启而丢失,这是非常致命的。
- 避免容器不断变大。
ENV
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
格式:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
COPY
复制指令,从上下文目录中复制文件或者目录到容器里指定路径。
格式:
COPY [--chown=<user>:<group>] <源路径1>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
[–chown=:]:可选参数,用户改变复制到容器内文件的拥有者和属组。
<源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match
规则。例如:
COPY hom* /mydir/
COPY hom?.txt /mydir/
<目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
ADD
ADD 指令和 COPY 的使用格式一致(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:
- ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到<目标路径>。
- ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
ENTRYPOINT
类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
但是, 如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 CMD 指令指定的程序。
优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。
注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
格式:
ENTRYPOINT ["<executeable>","<param1>","<param2>",...]
制作Dockerfile文件
做一个springboot应用的镜像,支持动态启动不同的jar
- 下载Java镜像
docker pull java:8
基于java镜像自定义配置文件
# 创建文件
touch Dockerfile
#编辑文件
vi Dockerfile
Dockerfile内容如下
FROM java:8
ADD /springboot-docker-0.0.1-SNAPSHOT.jar //
ENTRYPOINT [“java”, “-jar”, “/springboot-docker-0.0.1-SNAPSHOT.jar”]
构建镜像
当前路径下上传springboot-docker-0.0.1-SNAPSHOT,该文件需要大家根据自己需要构建
[root@localhost docker-workspace]# ls
Dockerfile springboot-docker-0.0.1-SNAPSHOT.jar
开始构建
docker build -t springboot .
[root@localhost docker-workspace]# docker build -t springboot .
Sending build context to Docker daemon 17.06MB
Step 1/3 : FROM java:8
---> d23bdf5b1b1b
Step 2/3 : ADD /springboot-docker-0.0.1-SNAPSHOT.jar //
---> e2a603ab9ecd
Step 3/3 : ENTRYPOINT ["java", "-jar", "/springboot-docker-0.0.1-SNAPSHOT.jar"]
---> Running in b514b318437b
Removing intermediate container b514b318437b
---> 4e291b60f844
Successfully built 4e291b60f844
Successfully tagged springboot:latest
查看镜像列表
[root@localhost docker-workspace]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
springboot latest d8de76659d3b 33 seconds ago 660MB
java 8 d23bdf5b1b1b 4 years ago 643MB
使用镜像运行容器
容器启动成功,结果如下:
docker run -d --name springboot-docker-c -p 10000:8080 springboot
# 容器命为springboot-docker-c
查看当前运行的容器
[root@localhost docker-workspace]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS
PORTS NAMES
acce1644be82 springboot "java -jar /springbo…" 18 seconds ago Up 15
seconds 0.0.0.0:10000->8080/tcp, :::10000->8080/tcp springboot-docker-c
查看log
# acce1644be82 为容器id
[root@bogon docker]# docker logs -f -t --tail 50 acce1644be82
2021-06-14T08:56:16.813287982Z
2021-06-14T08:56:16.813347726Z . ____ _ __ _ _
2021-06-14T08:56:16.813354739Z /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
2021-06-14T08:56:16.813359929Z ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
2021-06-14T08:56:16.813364668Z \\/ ___)| |_)| | | | | || (_| | ) ) ) )
2021-06-14T08:56:16.813369157Z ' |____| .__|_| |_|_| |_\__, | / / / /
2021-06-14T08:56:16.813373645Z =========|_|==============|___/=/_/_/_/
2021-06-14T08:56:16.849581197Z :: Spring Boot :: (v2.4.5)
2021-06-14T08:56:16.849634990Z
访问SpringBoot
镜像仓库
发布镜像到docker hub
前提
2021-06-14T08:56:17.604626919Z 2021-06-14 08:56:17.565 INFO 1 --- [
main] c.n.d.s.SpringbootDockerApplication : Starting
SpringbootDockerApplication v0.0.1-SNAPSHOT using Java 1.8.0_111 on acce1644be82
with PID 1 (/springboot-docker-0.0.1-SNAPSHOT.jar started by root in /)
2021-06-14T08:56:17.604693166Z 2021-06-14 08:56:17.600 INFO 1 --- [
main] c.n.d.s.SpringbootDockerApplication : No active profile set, falling
back to default profiles: default
2021-06-14T08:56:22.437778619Z 2021-06-14 08:56:22.435 INFO 1 --- [
main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s):
8080 (http)
2021-06-14T08:56:22.483275217Z 2021-06-14 08:56:22.478 INFO 1 --- [
main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2021-06-14T08:56:22.483305895Z 2021-06-14 08:56:22.479 INFO 1 --- [
main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache
Tomcat/9.0.45]
2021-06-14T08:56:22.759259752Z 2021-06-14 08:56:22.752 INFO 1 --- [
main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded
WebApplicationContext
2021-06-14T08:56:22.759309427Z 2021-06-14 08:56:22.752 INFO 1 --- [
main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext:
initialization completed in 4870 ms
2021-06-14T08:56:23.506626459Z 2021-06-14 08:56:23.498 INFO 1 --- [
main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService
'applicationTaskExecutor'
2021-06-14T08:56:24.169153444Z 2021-06-14 08:56:24.164 INFO 1 --- [
main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080
(http) with context path ''
2021-06-14T08:56:24.239297892Z 2021-06-14 08:56:24.231 INFO 1 --- [
main] c.n.d.s.SpringbootDockerApplication : Started
SpringbootDockerApplication in 9.148 seconds (JVM running for 12.299)
访问SpringBoot
镜像仓库
发布镜像到docker hub
前提
注册账号
docker hub官网注册 https://hub.docker.com/
客户端配置daemon.json
检查registry-mirrors和insecure-registries节点为缺省值,也就是[]
默认没有设置过就是缺省值
执行登陆
docker login
# 输入用户名和密码。
构建好自己的容器
比如springboot-docker
打包镜像
分为两种:
- 通过tag方式打包镜像
语法 docker tag imageName:version userName/imageName:version
docker tag springboot-docker:latest kojon/springboot-docker:latest
- 通过commit方式打包镜像
运行容器
docker run -d --name springboot-docker -p 8080:8080 springboot-docker
#此时通过docker ps -l 会得到一个容器id ef5f01dc4b9e
重新打包镜像
docker commit <容器名> <镜像名>
比如:
docker commit ef5f01dc4b9e kojon/springboot-docker
镜像命名规则
比如 kojon/springboot-docker 的镜像。
语法: userName/imageName
kojon是我的docker hub用户名,/前面要是你的用户名,才符合hub的规范
最后执行 push
docker push kojon/springboot-docker
阿里云docker hub
阿里云docker仓库
https://cr.console.aliyun.com/cn-hangzhou/instances/repositories
参考手册
https://cr.console.aliyun.com/repository/cn-hangzhou/dreamit/image-repo/details
(1)登录到阿里云docker仓库
sudo docker login --username=itcrazy2016@163.com
registry.cnhangzhou.aliyuncs.com
(2) 输入密码(3) 创建命名空间,比如itcrazy2016
(4) 给image打tag sudo docker tag [ImageId]
registry.cn-hangzhou.aliyuncs.com/itcrazy2016/testdocker-image:v1.0
(5)推送镜像到docker阿里云仓库sudo docker push
registry.cn-hangzhou.aliyuncs.com/itcrazy2016/test-dockerimage:v1.0
(6)别人下载,并且运行docker pull
registry.cn-hangzhou.aliyuncs.com/itcrazy2016/test-docker-image:v1.0
docker run -d --name user01 -p 6661:8080
registry.cnhangzhou.aliyuncs.com/itcrazy2016/test-docker-image:v1.0
docker搭建私有镜像仓库
官方参考 https://docs.docker.com/registry/configuration/
环境说明
角色 系统类型 IP
服务端 Centos 7 192.168.56.185
客户端 Centos 7 192.168.56.186
客户端 Windows 10 192.168.119.47
私服服务器下载registry镜像
在服务端下载私服镜像
[root@localhost registry]# docker pull registry
Using default tag: latest
latest: Pulling from library/registry
ddad3d7c1e96: Pull complete
6eda6749503f: Pull complete
363ab70c2143: Pull complete
5b94580856e6: Pull complete
12008541203a: Pull complete
Digest: sha256:bac2d7050dc4826516650267fe7dc6627e9e11ad653daca0641437abdf18df27
Status: Downloaded newer image for registry:latest
docker.io/library/registry:latest
运行registry镜像
docker run -itd -v /data/registry:/var/lib/registry --net=host --name kojon-registry registry:latest
run命令参数说明:
-
-a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;
-
-d: 后台运行容器,并返回容器ID;
-
-i: 以交互模式运行容器,通常与 -t 同时使用;
-
-P: 随机端口映射,容器内部端口随机映射到主机的端口
-
-p: 指定端口映射,格式为:主机(宿主)端口:容器端口
-
-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
-
–name=“nginx-lb”: 为容器指定一个名称;
-
–dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;
-
–dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;
-
-h “mars”: 指定容器的hostname;
-
-e username=“ritchie”: 设置环境变量;
-
–env-file=[]: 从指定文件读入环境变量;
-
–cpuset=“0-2” or --cpuset=“0,1,2”: 绑定容器到指定CPU运行;
-
-m :设置容器使用内存最大值;
-
–net=“bridge”: 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;
默认为bridge桥接,需要指定参数-p 来映射端口 参考-p参数
如果使用–net=host 即让容器和宿主机共享同一网络,容器内部运行程序的端口不能和宿主 机有冲突 -
–link=[]: 添加链接到另一个容器;
-
–expose=[]: 开放一个端口或一组端口;
-
–volume , -v: 绑定一个卷 将一个本地地址映射复制到docker内
示例如下:
# 运行镜像
[root@localhost registry]# docker run -itd -v /data/registry:/var/lib/registry -
p 5000:5000 --name kojon-registry registry:latest
47723102fe8d8ae35bce39744298f9dd916fa6515ed86805ceeaf693a4157410
查看日志:
[root@localhost registry]# docker logs -f -t --tail 500
47723102fe8d8ae35bce39744298f9dd916fa6515ed86805ceeaf693a4157410
2021-05-19T08:47:05.128492112Z WARN[0000] No HTTP secret provided - generated
random secret. This may cause problems with uploads if multiple registries are
behind a load-balancer. To provide a shared secret, fill in http.secret in the
configuration file or set the REGISTRY_HTTP_SECRET environment variable.
go.version=go1.11.2 instance.id=aaec4b0e-266e-45f0-9876-e9713a879488
service=registry version=v2.7.1
2021-05-19T08:47:05.128560572Z INFO[0000] redis not configured
go.version=go1.11.2 instance.id=aaec4b0e-266e-45f0-9876-e9713a879488
service=registry version=v2.7.1
2021-05-19T08:47:05.138087303Z INFO[0000] Starting upload purge in 25m0s
go.version=go1.11.2 instance.id=aaec4b0e-266e-45f0-9876-e9713a879488
service=registry version=v2.7.1
2021-05-19T08:47:05.151680721Z INFO[0000] using inmemory blob descriptor cache
go.version=go1.11.2 instance.id=aaec4b0e-266e-45f0-9876-e9713a879488
service=registry version=v2.7.1
2021-05-19T08:47:05.158031343Z INFO[0000] listening on [::]:5000
go.version=go1.11.2 instance.id=aaec4b0e-266e-45f0-9876-e9713a879488
service=registry version=v2.7.1
访问私服
- 如果有防火墙,请先关闭或者添加TCP入口规则
防火墙命令
#查看防火墙运行状态
systemctl status firewalld
#关闭防火墙
service firewalld stop
- 访问: http://192.168.56.185:5000/v2/_catalog
此时私服上还没有镜像,接下来配置好客户端就可以上传镜像了。
客户端配置daemon.json
官方配置参 https://docs.docker.com/engine/reference/commandline/dockerd/
默认缺省值是上传到docker hub上
{ “registry-mirrors”: [], “insecure-registries”: [], … other
info}
“registry-mirrors”: [
“https://registry.hub.docker.com”], “insecure-registries”: [
“registry.hub.docker.com”] … other info
}
需要修改为指定的仓库时,修改此处的insecure-registries的值
centos7客户端
创建daemon.json配置文件
创建并写入值
echo '{ "insecure-registries":["192.168.56.185:5000"] }' > /etc/docker/daemon.json
重启docker服务
sudo systemctl daemon-reload
sudo systemctl restart docker
windows10客户端
打开docker desktop
设置通讯开关
设置私服仓库地址,并重启
客户端发布镜像
打tag
语法 docker tag imageName:version registry address/userName/imageName:version
docker tag springboot-docker:latest 192.168.56.185:5000/kojon/springbootdocker:latest
push 到仓库
语法 docker push registry-address/userName/imageName:version
docker push 192.168.56.185:5000/kojon/springboot-docker
docker命令是跨平台的,linux命令也如下:
PS C:\Users\OnlyC> docker images
REPOSITORY TAG IMAGE ID CREATED
SIZE
springboot-docker latest 79f9b1219197 3 hours
ago 643MB
java latest d23bdf5b1b1b 4 years
ago 643MB
PS C:\Users\OnlyC> docker tag springboot-docker:latest
192.168.56.185:5000/kojon/springboot-docker:latest
PS C:\Users\OnlyC> docker images
REPOSITORY TAG IMAGE ID CREATED
SIZE
192.168.56.185:5000/kojon/springboot-docker latest 79f9b1219197 3 hours
ago 643MB
springboot-docker latest 79f9b1219197 3 hours
ago 643MB
java latest d23bdf5b1b1b 4 years
ago 643MB
PS C:\Users\OnlyC> docker push 192.168.56.185:5000/kojon/springboot-docker
Using default tag: latest
The push refers to repository [192.168.56.185:5000/kojon/springboot-docker]
35c20f26d188: Pushed
c3fe59dd9556: Pushed
6ed1a81ba5b6: Pushed
a3483ce177ce: Pushed
ce6c8756685b: Pushed
30339f20ced0: Pushed
0eb22bfb707d: Pushed
a2ae92ffcd29: Pushed
latest: digest:
sha256:da8f846f6754fd60e2be2895b4816bdb43c745c38f390923f646dd831e4369e3 size:
2000
windows上可以使用docker desktop 来push
搭建自己的Docker Harbor
(1)访问github上的harbor项目
https://github.com/goharbor/harbor
(2)下载版本,比如1.7.1
https://github.com/goharbor/harbor/releases
官方演示地址:https://demo.goharbor.io/harbor
账号admin 密码Harbor12345
(3) 找一台安装了docker-compose[这个后面的课程会讲解],上传并解压tar -zxvf xxx.tar.gz
(4) 进入到harbor目录
修改harbor.cfg文件,主要是ip地址的修改成当前机器的ip地址
同时也可以看到Harbor的密码,默认是Harbor12345
(5) 安装harbor,需要一些时间
sh install.sh
(6) 浏览器访问,比如192.168.56.185:8080,输入用户名和密码即可
深入探讨Container
既然container是由image运行起来的,那么是否可以理解为container和image有某种关系?
理解 :其实可以理解为container只是基于image之后的layer而已,也就是可以通过docker run image 创建出一个container出来。
container到image
既然container是基于image之上的,想想是否能够由一个container反推出image呢?
肯定是可以的,比如通过docker run运行起一个container出来,这时候对container对一些修改,然后
再生成一个新的image,这时候image的由来就不仅仅只能通过Dockerfile咯。
(1) 拉取一个centos image docker pull centos (2) 根据centos镜像创建出一个container
docker run -d -it --name my-centos centos (3) 进入my-centos容器中docker exec -it my-centos bash (4) 输入vim命令
bash: vim: command not found (5) 我们要做的是
对该container进行修改,也就是安装一下vim命令,然后将其生成一个新的centos (6)
在centos的container中安装vim yum install -y vim (7)
退出容器,将其生成一个新的centos,名称为"vim-centos-image"语法 docker commit container-name newImage-name docker commit my-centos
vim-centos-image (8) 查看镜像列表,并且基于"vim-centos-image"创建新的容器docker run -d -it --name my-vim-centos vim-centos-image (9)
进入到my-vim-centos容器中,检查vim命令是否存在docker exec -it my-vim-centos bash
结论 :可以通过docker commit命令基于一个container重新生成一个image,但是一般得到image的方式不建议这么做,不然image怎么来的就全然不知咯。
container资源限制
如果不对container的资源做限制,它就会无限制地使用物理机的资源,这样显然是不合适的。
查看资源情况 :docker stats
内存限制
–memory Memory limit
如果不设置 --memory-swap,其大小和memory一样
docker run -d --memory 100M --name tomcat1 tomcat
CPU限制
–cpu-shares 权重
docker run -d --cpu-shares 10 --name tomcat2 tomcat
图形化资源监控
https://github.com/weaveworks/scope
sudo curl -L git.io/scope -o /usr/local/bin/scope
sudo chmod a+x /usr/local/bin/scope
scope launch 39.100.39.63
#停止scope
scope stop
#同时监控两台机器,在两台机器中分别执行如下命令scope launch ip1 ip2
container常见操作
(1) 根据镜像创建容器
docker run -d --name -p 9090:8080 my-tomcat tomcat
(2) 查看运行中的container
docker ps
(3) 查看所有的container[包含退出的] docker ps -a
(4) 删除container
docker rm containerid docker rm -f $(docker ps -a) 删除所有container
(5)进入到一个container中
docker exec -it container bash
(6) 根据container生成image docker
(7)查看某个container的日志docker logs container
(8) 查看容器资源使用情况
docker stats
(9) 查看容器详情信息
docker inspect container
(10) 停止/启动容器
docker stop/start container
底层技术支持
Container是一种轻量级的虚拟化技术,不用模拟硬件创建虚拟机。
Docker是基于Linux Kernel的Namespace、CGroups、UnionFileSystem等技术封装成的一种自定义容器格式,从而提供一套虚拟运行环境。
Namespace:用来做隔离的,比如pid[进程]、net[网络]、mnt[挂载点]等
CGroups: Controller Groups用来做资源限制,比如内存和CPU等
Union file systems:用来做image和container分层