安装
https://docs.docker.com/install/
https://docs.docker.com/install/linux/docker-ce/centos/
二进制方式安装
https://docs.docker.com/install/linux/docker-ce/binaries/
mac安装
https://docs.docker.com/docker-for-mac/install/
windows10 安装
https://docs.docker.com/docker-for-windows/install/
镜像
什么是image
什么是layer
搜索下载镜像
镜像打标签,使用标签
什么是image
image = files + metadata
files
文件是构建容器的根文件系统
metadata
包含一些元数据信息
- 镜像维护者
- 启动时执行的command
- 设置环境变量
images由一层层的files相互堆叠起来, 每一层都可以添加/修改/文件;元数据信息, 镜像层级共享可以节省空间,内存,网络传输消耗等.
例子: 一个java webapp镜像各个镜像层信息
- CentOS base layer
- 基础包与配置依赖
- JRE
- Tomcat
- java webapp 运行时jar依赖
- java webapp 代码
- java webapp 配置
容器镜像区别
镜像是一个只读的文件
容器是在该文件系统的读写副本中运行的一组封装的进程。
为了优化容器启动时间,使用写时拷贝而不是常规拷贝。
docker run从给定的image启动容器。
镜像容器与面向对象中概念
- image概念上类似类(一些成员属性数据)
- layer概念上类似类的继承
- 容器类似实例
镜像基本操作
修改镜像
镜像是只读的,如果我们需要对镜像进行修改以适应自己需求,我们无法修改原有镜像!
但是我们可以基于此镜像进行修改生成新的镜像,而新的镜像是通过旧的镜像基础修改而来
创建镜像
首先得有一个容器
, 而创建一个容器
必须得先有镜像
,死循环!
解决方法
创建一个基础的镜像
,生成新的的镜像后,再封装成我们所需要的镜像
https://docs.docker.com/samples/library/scratch/
https://docs.docker.com/develop/develop-images/baseimages/
也可以使用 docker import
命令导入tarball
压缩的docker镜像
镜像生成
生成新的镜像有两种方法
docker commit
基于现存容器生成一个新的镜像(很少使用此方法)
$ docker commit aae5ef258c76 zrd/flanneld:v1
sha256:f46a5c369b4f938a5e2b9498813227f5174b54d6601f76d3a2da1eec6367e4f3
docker build
(99%情况下使用此方法)
Images namespaces命名空间
我们拉取镜像时有以下几种方式
- 1.默认拉取官方封装好的镜像(官方: 启动docker所设置的docker RegistryURl)
docker pull centos
- 2.拉取指定用户构建的镜像
docker pull zhourudong/myweb
- 3.完整的地址
docker pull registry.example.com:5000/my-private/image
root namespaces一般由官方创建维护比如我们所用的镜像CentOS, mysql
User namespace一般由用户基于root namespaces
自创的镜像例如cucy/busybox
,其中cucy
是用户名,busybox
为镜像
Self-hosted namespace此命名空间保存的图像不在Docker Hub上,而是在第三方自定义, 例如
quay.io/coreos/etcd
gcr.io/google-containers/hugo
localhost:5000/wordpress
quay.io, gcr.io, localhost:5000
是仓库的地址,etcd,hugo,wordpress
是镜像
镜像保存管理
保存镜像的方法:
本机
Remote Docker registry
我们可以使用docker client下载(pull),上传(push)镜像,严格来说是docker client给docker engine发送pull, post请求,由docker
显示本地所有镜像
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
zrd/flanneld v1 f46a5c369b4f About an hour ago 52.6MB
findsec/hello v2 72f0edcf0c06 4 days ago 941MB
findsec/hello v1 c54843059b2b 4 days ago 941MB
calico/node v3.8.0 cd3efa20ff37 10 days ago 155MB
calico/cni v3.8.0 539ca36a4c13 10 days ago 143MB
calico/kube-controllers v3.8.0 df5ff96cd966 10 days ago 46.8MB
calico/pod2daemon-flexvol v3.8.0 f68c8f870a03 13 days ago 9.37MB
gcr.azk8s.cn/google-containers/kube-proxy v1.15.0 d235b23c3570 3 weeks ago 82.4MB
搜索镜像
# docker search busybox
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
busybox Busybox base image. 1623 [OK]
progrium/busybox 70 [OK]
radial/busyboxplus Full-chain, Internet enabled, busybox made f… 24 [OK]
arm32v7/busybox Busybox base image. 7
yauritux/busybox-curl Busybox with CURL 5
armhf/busybox Busybox base image. 4
arm64v8/busybox Busybox base image. 3
OFFICIAL
表示是官方镜像
AUTOMATED
自动构建
下载镜像
docker pull指定下载镜像
docker run当本地没有此镜像时,会到docker仓库进行拉取
tag打标签
docker tag busybox:latest zrd:prod-v1
适合使用标签场景
快速测试使用
正在开发环境调式
使用latest版本
适合打标签场景
在脚本中定义版本信息
生产环境
重复使用
练习
从基础镜像运行一个容器
安装一些基础软件,然后生成新的镜像
使用docker commit, docker tag, and docker diff
等命令
主机上执行
# docker run -it centos
容器内运行
[root@1e42384795b3 /]# yum install wget -y && rm -rf /var/cache/yum
容器所修改的内容
[root@k8s-master-45 ~]# docker diff fb62137afd63
C /usr
C /usr/bin
A /usr/bin/wget
C /usr/share
C /usr/share/locale
C /usr/share/locale/en_GB
C /usr/share/locale/en_GB/LC_MESSAGES
A /usr/share/locale/en_GB/LC_MESSAGES/wget.mo
主机上执行 $ docker commit <yourContainerId>
# docker commit fb62137afd63 zrd/centostest
**镜像是只读,当我们对其进行修改时,它会拷贝修改的文件到新的镜像, **, 基于性能出发点,docker使用copy-on-write技术
验证生成的镜像
# docker run zrd/centostest wget baidu.com
--2019-07-12 09:44:48-- http://baidu.com/
Resolving baidu.com (baidu.com)... 123.125.114.144, 220.181.38.148
Connecting to baidu.com (baidu.com)|123.125.114.144|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 81 [text/html]
Saving to: 'index.html'
0K 100% 12.9M=0s
2019-07-12 09:44:48 (12.9 MB/s) - 'index.html' saved [81/81]
打标签
两种打标签方法
$ docker tag <newImageId> figlet
$ docker commit <containerId> figlet
以上构建镜像方法过于繁杂, Dockerfile应运而生
使用Dockerfile来构建镜像
$ vim Dockerfile
FROM ubuntu
RUN apt-get update
RUN apt-get install figlet
FROM 指定从哪个基础镜像开始构建
RUN 每一个RUN指令就是构建一个镜像, RUN 运行的命令不能有交互
$ docker build -t figlet .
-t 表示指定标签
. 表示以当前目录下Dockerfile
中所定义的步骤进行构建镜像
构建时,显示的内容
[root@k8s-master-45 ~/myimage]# docker build -t figlet .
Sending build context to Docker daemon 2.048kB
Step 1/3 : FROM ubuntu
---> 4c108a37151f
Step 2/3 : RUN apt-get update
---> Running in 6c0d73559f78
Removing intermediate container 5e624609a7f1
---> 81def0f272fc
Successfully built 81def0f272fc
Successfully tagged figlet:latest
context
Sending build context to Docker daemon 2.048kB
因为docker client 和Docker daemon(Engine)可以在不同的主机上,在构建时,docker client 需要将本地数据上传给docker daemo(压缩); 在构建时如果docker client 和docker engine不在同一台主机上时,上传本地文件数据会耗费很长的时间
docker build --no-cache
docker history figlet
CMD and ENTRYPOINT
CMD / ENTRYPOINT
这两个命令可以设置容器启动时容器运行的命令参数
CMD
FROM ubuntu
RUN apt-get update
RUN ["apt-get", "install", "figlet"]
CMD figlet -f script hello
不加指定参数默认以CMD定义的命令来运行
[root@k8s-master-45 ~/myimage]# docker run figlet
_ _ _
| | | | | |
| | _ | | | | __
|/ |/ |/ |/ / \_
| |_/|__/|__/|__/\__/
覆盖
CMD
默认设定的命令
$ docker run -it figlet bash
root@7ac86a641116:/#
ENTRYPOINT
FROM ubuntu
RUN apt-get update
RUN ["apt-get", "install", "figlet"]
ENTRYPOINT ["figlet", "-f", "script"]
运行测试
$ docker run figlet salut
_
| |
, __, | | _|_
/ \_/ | |/ | | |
/ \_/|_/|__/ \_/|_/|_/
使用 CMD 还是 ENTRYPOINT?
两个可以同时并存, ENTRYPOINT
作为基本执行命令不会被覆盖,如果使用CMD
命令会被全部覆盖;所以ENTRYPOINT
作为容器的基本命令,而CMD
定义为默认的参数
FROM ubuntu
RUN apt-get update
RUN ["apt-get", "install", "figlet"]
ENTRYPOINT ["figlet", "-f", "script"]
CMD ["hello world"]
以上例子,当容器运行后,如果不给参数则命令 CMD
是默认的参数; 如果启动时给定参数,CMD
设置的参数会被覆盖.
# docker build -t figlet .
Sending build context to Docker daemon 2.048kB
Step 1/5 : FROM ubuntu
....
以默认参数运行
# docker run figlet
_ _ _ _
| | | | | | | | |
| | _ | | | | __ __ ,_ | | __|
|/ |/ |/ |/ / \_ | | |_/ \_/ | |/ / |
| |_/|__/|__/|__/\__/ / / \__/ |_/|__/\_/|_/
覆盖默认参数
# docker run figlet 123
, __ ___
/|/ )/
| / __/
| /
|/___\___/
强制覆盖ENTRYPOINT
我们可以使用--entrypoint
覆盖基本命令
$ docker run -it --entrypoint bash figlet
root@6027e44e2955:/#
CPOY /ADD
时候构建代码时,代码并不在容器中(在宿主机上), 我们需要使用COPY 或者ADD命令将本地文件拷贝到容器中
代码内容如下
# cat hellogo.go
package main
func main() {
println("Hi, golang!")
}
Dockerfile
FROM ubuntu
RUN apt-get update
RUN apt-get install -y golang
COPY hellogo.go /
RUN GOPATH=/ && go build -o hellogo .
CMD /hellogo
CPOY /ADD类似,
ADD
可以解压压缩文件(展开压缩文件的内容,而不是把整个压缩包往容器里添加)
减少镜像大小
以最小依赖来安装软件包, 构建完成前可以清理一些缓存,比如apt yum 的cache目录
docker image build --squash ...
压缩成单一层镜像
Multi-stage builds 多阶段构建
FROM ubuntu AS compiler
RUN apt-get update
RUN apt-get install -y golang
COPY hellogo.go /
RUN GOPATH=/ && go build -o hellogo .
FROM ubuntu
COPY --from=compiler hellogo.go /
CMD /hellogo
镜像仓库管理
docker login
# 登录信息会保存在 ~/.docker/config
docker target image someimage zrd/someimage
docker push zrd/someimage
Dockerfile tip
entrypoint script
#!/bin/sh
set -e
# first arg is '-f' or '--some-option'
# or first arg is 'something.conf'
if [ "${1#-}" != "$1" ] || [ "${1%.conf}" != "$1" ]; then
set -- redis-server "$@"
fi
# allow the container to be started with '--user'
if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then
chown -R redis .
exec su-exec redis "$0" "$@"
fi
exec "$@"
$ docker inspect --format '{{ json .Created }}' <containerID>
"2015-02-24T07:21:11.712240394Z"
docker label
docker run -d -l owner=alice nginx
docker run -d -l owner=bob nginx
docker run -d -l owner nginx
$ docker inspect $(docker ps -lq) | grep -A3 Labels
"Labels": {
"maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>",
"owner": ""
},
$ docker inspect $(docker ps -q) --format 'OWNER={{.Config.Labels.owner}}'
$ docker ps --filter label=owner
Or we can list containers having a specific label with a specific value.
$ docker ps --filter label=owner=alice
docker cp <container_id>:/var/log/nginx/error.log .
docker run -ti --entrypoint sh debugimage
资源限制
内存
docker run -ti --memory 100m python
cpu
--cpus 0.1 means 10% of one CPU,
--cpus 1.0 means 100% of one whole CPU,
--cpus 10.0 means 10 entire CPUs.
--cpuset-cpus 0 forces the container to run on CPU 0;
--cpuset-cpus 3,5,7 restricts the container to CPUs 3, 5, 7;
--cpuset-cpus 0-3,8-11 restricts the container to CPUs 0, 1, 2, 3, 8, 9, 10, 11.
docker 网路
docker run --net none ...
单网络容器
!()[bridge1.png]
Two containers on a single Docker network
!()[bridge2.png]
Two containers on two Docker networks
!()[bridge3.png]
创建网络
docker network create dev
$ docker run -d --name es --net dev elasticsearch:2
$ docker run -ti --net dev alpine sh
$ docker run --net dev --net-alias redis -d redis
--internal
--gateway
--subnet
--ip-range
--aux-address
$ docker network create --subnet 10.66.0.0/16 pubnet
$ docker run --net pubnet --ip 10.66.66.66 -d nginx
docker network connect <network> <container>
docker network disconnect <network> <container>
docker network connect dev <container_id>