Docker解决了以上问题,以前我们开发都是打个jar或war包交给运维来部署,现在使用Docker会将jar + 环境打包生成个镜像放在镜像仓库,直接下载我们的镜像运行即可。
Docker的核心思想其实来源于集装箱,每个箱子都是相互隔离的,其中一个箱子出问题不会影响其他箱子。举个例子:
假如我们使用的Linux系统就是这个鲸鱼,没有集装箱的时候,我们不能把毒药和水果放在一起吧,放在一起会出问题的,但是有了集装箱以后,我们可以一个集装箱放水果,一个集装箱放毒药,互不影响。Docker的出现可以让Linux的空间得到极大的利用。
Docker是基于Go语言开发的。相比于早期的虚拟机技术,最大的优点就是轻巧!Docker隔离、镜像(比如jdk、mysql、redis…)非常小巧,运行镜像也就几兆,有的甚至几KB。而VMware等动则几个G甚至十几个G。
DevOps(开发运维)
应用更快速的交付、部署
传统:一堆帮助文档、安装程序
Docker:打包镜像发布测试,一键运行
更便捷的升级和扩容
使用了Docker,部署应用就像搭积木一样
项目打包为一个镜像,扩展服务器A、服务器B…
更简单的系统运维
在容器化之后,我们的开发、测试环境都是高度一致的
更高效的计算资源利用
Docker是内核级别的虚拟化,可以在一个物理机上运行很多的容器实例,服务器的性能可以被压缩到极致!
文档地址:https://docs.docker.com/engine/install/centos/
卸载旧版本
$ sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
安装 yum-utils 包(它提供 yum-config-manager 实用工具)并设置稳定存储库。
sudo yum install -y yum-utils
设置默认仓库
$ sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo #默认是国外的
sudo yum-config-manager --add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo #阿里云镜像
安装最新版本的 Docker Engine 和 containerd, docker-ce社区版,docker-ee企业版
$ sudo yum install docker-ce docker-ce-cli containerd.io
启动Docker
$ sudo systemctl start docker
通过运行 hello-world 映像来验证 Docker Engine 安装是否正确。
$ sudo docker run hello-world
查看镜像
docker images
卸载Docker
$ sudo yum remove docker-ce docker-ce-cli containerd.io
$ sudo rm -rf /var/lib/docker
登录阿里云
找到 容器镜像服务
如果没有就创建一个
点击镜像加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://maculvvb.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
帮助命令
docker version
docker info
docker --help
帮助文档:https://docs.docker.com/engine/reference/commandline/docker/
文档地址:https://docs.docker.com/engine/reference/commandline/images/
docker images [OPTIONS] [REPOSITORY[:TAG]]
Name, shorthand | Default | Description |
---|---|---|
--all , -a |
显示所有镜像(默认隐藏当前镜像) | |
--digests |
展示摘要 | |
--filter , -f |
基于提供的条件的过滤器输出 | |
--format |
使用 Go 模板的漂亮打印图像 | |
--no-trunc |
不要截断输出 | |
--quiet , -q |
只显示数字 id |
文档地址: https://docs.docker.com/engine/reference/commandline/search/
docker search [OPTIONS] TERM
Name, shorthand | Default | Description |
---|---|---|
--automated |
只显示自动构建 | |
--filter , -f |
基于提供的条件的过滤器输出 | |
--format |
使用 Go 模板进行漂亮印刷的搜索 | |
--limit |
25 |
搜寻结果的最大数目 |
--no-trunc |
不要截断输出 | |
--stars , -s |
只显示至少 x 颗星星 |
文档地址:https://docs.docker.com/engine/reference/commandline/push/
docker push [OPTIONS] NAME[:TAG]
Name, shorthand | Default | Description |
---|---|---|
--disable-content-trust |
true |
跳过镜像签名 |
文档地址:https://docs.docker.com/engine/reference/commandline/rmi/
docker rmi [OPTIONS] IMAGE [IMAGE...]
Name, shorthand | Default | Description |
---|---|---|
--force , -f |
强制删除镜像 | |
--no-prune |
不删除无标签的 |
docker pull centos
docker run [可选参数] image
#参数说明
--name 容器名字
-d 后台方式运行
-it 交互方式运行 进入容器查看内容
-p 指定端口 -p 8080:8080 和主机的端口映射
-p IP:主机端口:容器端口
-p 主机端口:容器端口(常用)
-p 容器端口
容器端口
-P 随机映射端口
docker run -it centos /bin/bash
docker ps
-a #列出当前正在运行的容器+历史运行过的容器
-n=? #显示最近创建的容器
-q #只显示容器的编号
exit #退出并停止容器
Ctrl + P + Q # 容器不停止退出
docker rm 容器ID # 删除指定容器,不能删除正在运行的容器
docker rm -f $(docker ps -aq) #删除所有容器
docker ps -a -q|xargs docker rm #删除所有容器
docker start 容器ID # 启动容器
docker restart 容器ID # 重启容器
docker stop 容器ID #停止容器
docker kill 容器ID # 强制停止当前容器
docker run -d 镜像名
docker logs 容器ID
docker logs --help
Options:
--details Show extra details provided to logs
-f, --follow Follow log output
--since string Show logs since timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)
--tail string Number of lines to show from the end of the logs (default "all")
-t, --timestamps Show timestamps
--until string Show logs before a timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)
docker logs -tf --tail 10 #查看最新10条日志
docker top 容器ID
docker inspect --help
Options:
-f, --format string Format the output using the given Go template
-s, --size Display total file sizes if the type is container
--type string Return JSON for specified type
docker inspect 0ed9c92a3359
[
{
"Id": "0ed9c92a3359a4562115989cc1686f1c28b9e779385e8d5538f7cad4836f6d5f",
"Created": "2020-07-07T00:36:11.958148146Z",
"Path": "docker-entrypoint.sh",
"Args": [
"mysqld"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 21414,
"ExitCode": 0,
"Error": "",
"StartedAt": "2020-07-07T00:47:16.979329147Z",
"FinishedAt": "2020-07-07T00:47:16.63257377Z"
},
"Image": "sha256:44a8e1a5c0b27650237907f4e9ee7fccdba0120291d27075e2cb8c8e8a8ec66b",
"ResolvConfPath": "/var/lib/docker/containers/0ed9c92a3359a4562115989cc1686f1c28b9e779385e8d5538f7cad4836f6d5f/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/0ed9c92a3359a4562115989cc1686f1c28b9e779385e8d5538f7cad4836f6d5f/hostname",
"HostsPath": "/var/lib/docker/containers/0ed9c92a3359a4562115989cc1686f1c28b9e779385e8d5538f7cad4836f6d5f/hosts",
"LogPath": "/var/lib/docker/containers/0ed9c92a3359a4562115989cc1686f1c28b9e779385e8d5538f7cad4836f6d5f/0ed9c92a3359a4562115989cc1686f1c28b9e779385e8d5538f7cad4836f6d5f-json.log",
"Name": "/mymysql",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": [
"e0bfc0c67ff4d16cc70f83a47fed2f9eba37b8f42ab7db68cadf04da5b5519a1"
],
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {
"3306/tcp": [
{
"HostIp": "",
"HostPort": "3306"
}
]
},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"Capabilities": null,
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/4e4d51419c11cb22784160aa0ec2d9439d3c0b96de6c7d60cf8b503871c99859-init/diff:/var/lib/docker/overlay2/d80494f65004d34717bc6c791cbe881729fd2c0846b3f2e0154ffaf95425d1c6/diff:/var/lib/docker/overlay2/ca45ec4c3bd06a2ef9503df96d7ba32912aee58fa9f8f4cfac2c2b28a6358662/diff:/var/lib/docker/overlay2/02f46b0788697cc0cc150afba025648d24c18ce56307a32b9986140f4fe860d4/diff:/var/lib/docker/overlay2/581596595f1448614c334eb470481fc70a638601f1f81ebe63d6ff8f9f45330e/diff:/var/lib/docker/overlay2/404848294a3253d680450f61ee901ed76c63b9339904ba70e5cd505041414e11/diff:/var/lib/docker/overlay2/5cdba39d722214767eb4fc8040f6222e9582330d5e1910cc44898b88906ff403/diff:/var/lib/docker/overlay2/f201bf786f050af48f5b1f0d6c949bf0f7942c4433b3167c57fc80d7a96d8e6d/diff:/var/lib/docker/overlay2/76d7620a0bc93ba249a614d6b4e201982e99fe5285ed81fb68d6957bce6b61df/diff:/var/lib/docker/overlay2/ab95b6395ae0e52ca93a7224d17fabc1c0ce4b4e145908cace83968e6f2716c2/diff:/var/lib/docker/overlay2/4250bddc52068730181d0b22be7c889963582e43806c49c5c26740f948fcaedb/diff:/var/lib/docker/overlay2/79fc77b97e314b9f4f15be663c2df80b23a9ea8004897c0e2f2301e2260f5d67/diff",
"MergedDir": "/var/lib/docker/overlay2/4e4d51419c11cb22784160aa0ec2d9439d3c0b96de6c7d60cf8b503871c99859/merged",
"UpperDir": "/var/lib/docker/overlay2/4e4d51419c11cb22784160aa0ec2d9439d3c0b96de6c7d60cf8b503871c99859/diff",
"WorkDir": "/var/lib/docker/overlay2/4e4d51419c11cb22784160aa0ec2d9439d3c0b96de6c7d60cf8b503871c99859/work"
},
"Name": "overlay2"
},
"Mounts": [
{
"Type": "volume",
"Name": "86b9eec00f8d1e9cb4a9bce274ab418fd87d7d58d0a15981f45ed4e9a6e19270",
"Source": "/var/lib/docker/volumes/86b9eec00f8d1e9cb4a9bce274ab418fd87d7d58d0a15981f45ed4e9a6e19270/_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
"Config": {
"Hostname": "0ed9c92a3359",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"3306/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"MYSQL_ROOT_PASSWORD=123456",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.7",
"MYSQL_MAJOR=5.7",
"MYSQL_VERSION=5.7.18-1debian8"
],
"Cmd": [
"mysqld"
],
"Image": "mysql:5.7.18",
"Volumes": {
"/var/lib/mysql": {}
},
"WorkingDir": "",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "47a98d0324694a55361b2ca5ce2838a648f8023ba1724ac395f74efb978b3e03",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"3306/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "3306"
}
]
},
"SandboxKey": "/var/run/docker/netns/47a98d032469",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "f3310c3928294d7edbc20ec1847b34996ec691e382bf1d4a3ca645e498387c77",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:03",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "e6ff23e009d3b064d64225694d33eae351285942c60d91d90c3b09834dd85f31",
"EndpointID": "f3310c3928294d7edbc20ec1847b34996ec691e382bf1d4a3ca645e498387c77",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:03",
"DriverOpts": null
}
}
}
}
]
docker exec -it 容器ID /bin/bash #进入容器后开启新的终端
docker attach 容器ID # 进入容器正在执行的终端,不会启动新的进程
docker cp 容器ID:容器内路径 宿主机路径
docker stats
attach Attach to a running container #当前she11下attach 连接指定运行镜像
build Build an image from a Dockerfile #通过Dockerfile定制镜像
commit Create a new image from a container changes #提交当前容器为新的镜像
cp Copy files/folders from the containers filesystem to the host path #从容器中拷贝指定文件或者目录到宿主机中
create Create a new container #创建一个新的容器,同run, 但不启动容器
diff Inspect changes on a container's fi lesystem #查看docker容器变化
events Get rea1 time events from the server #从docker 服务获取容器实时事件
exec Run a command in an existing container #在已存在的容器上运行命令
export Stream the contents of a container as a tar archive #导出容器的内容流作为一个tar 归档文件【对应
import
history Show the history of an image #展示一个镜像形成历史
images List images #列出系统当前镜像
import Create a new filesystem image from the contents of a tarba11 #从tar包中的内容创建个新的文件系统映像【对应export】
info Display system一wide information #显示系统相关信息
inspect
Return 1ow一1eve1 information on a container #查看容器详细信息
ki11 Ki11 a running container # ki11指定docker 容器
load Load an timage from a tar archive #从一个tar包中加载一个镜像【对应save】
login Register or Login to the docker registry server #注册或者登陆一个docker源服务器
logout Log out from a Docker registry server #从当前Docker registry 退出
logs Fetch the logs of a container #输出当前容器日志信息
port Lookup the public-facing port which is NAT-ed to PRIVATE_PORT #查看映射端口对应的容器内部源端口
pause Pause a11 processes within a container #暂停容器
ps List containers #列出容器列表
pu11 Pu11 an image or a repository from the docker registry server #从docker镜像源服务器拉取指定镜像或者库镜像
push Push an image or a repository to the docker registry server #推送指定镜像或者库镜像至docker源服务器
restart Restart a running container #重启运行的容器
rm Remove one or more containers #移除一个或者多个容器
rmi Remove one or more images #移除一个或多个镜像【无容器使用该镜像才可删除,否则需删除相关容器才可继续或-f强制删除】
run Run a command in a new container #创建一个新的容器并运行一个命令
save Save an image to a tar archive #保存一个镜像为一个tar包【对应1oad】
search Search for an image on the Docker Hub #在docker hub中搜索镜像
start Start a stopped containers #启动容器
stop Stop a running containers #停止容器
tag Tag an image into a repository #给源中镜像打标签
top Lookup the running processes of a container #查看容器中运行的进程信息
unpause Unpause a paused container #取消暂停容器
version Show the docker version informati on #查看docker版本号
wait B1ock until a container. stops,then print its exit code #截取容器停止时的退出状态值
下载镜像
docker pull nginx
启动容器
docker images
docker run -d --name nginx01 -p 3344:80 nginx
# -d 后台运行
# --name 给容器起个名
# -p 将公网的3344端口暴露给容器的80端口
下载Tomcat镜像
docker pull tomcat
运行容器
docker run -d --name tomcat01 -p 3355:8080 tomcat
# es暴露的端口十分多
# es十分耗内存
# es的数据一般要挂载到安全目录
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPS="-Xms64m -Xmx512m" elasticsearch:7.6.2
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
所有的应用,植接打包docker镜像,就可以直接跑起来!
UnionFS (联合文件系统)
我们下载的时候看到的一层层就是这个!
UnionFS (联合文件系统) : Union文件系统( UnionFS)是一种分层、 轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtualfilesystem)。Uniqn 文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引|导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs.
rootfs (root file system) , 在bootfs之上。包含的就是典型Linux 系统中的/dev, /proc, /bin, /etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu , Centos等等。
平时我们安装进虚拟机的CentOS都是好几个G ,为什么Docker这里才200M ?
它是一个精简的OS,只需要包含最精简的命令,因为底层使用系统的Kernel,自己只需要提供rootfs就好了
所有的Docker镜像都起始于一个基础镜像层 ,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。
举一个简单的例子,假如基于 Ubuntu Linux 16.04创建一个 新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁, 就会创建第三个镜像层。
该镜像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子 )。
在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。 下图中举 了一个简单的例子,每个镜像包含3个文件,而镜像包含了来自两个镜像层的6个文件。
上图中的镜像层跟之前图中的略有区别,主要目的是便于展示文件。
下图中示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7文件5的一个更新版本。
这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。Docker通过存储弓|擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件 系统。
Linux.上可用的存储引擎有AUFS、Overlay2、 Device Mapper. Btrfs 以及ZFS。顾名思义,每种存储弓|擎都基于Linux中对应的文件系统或者块设备技术,并且每种存储弓|擎都有其独有的性能特点。
Docker在Windows.上仅支持windowsfilter 一种存储引擎,该引擎基于NTFS文件系统之上实现了分层和CoW【1】。
下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。
特点
Docker镜像是只读的,当容器启动时,一个新的可写层被加载到镜像顶部,这一层就是我们说的容器层,容器之下的叫镜像层!
docker commit 提交容器成为一个新的副本
docker commit -m="提交的描述信息" -a="作者" 容器ID 目标镜像名:[TAG]
测试commit Tomcat镜像
下载Tomcat镜像
docker pull tomcat
启动
docker run -d -p 8080:8080 tomcat
进入容器
docker exec -it 885a68576f0a /bin/bash
进入webapps
cd webapps
发现什么都没有
从webapp.dist中拷贝出所有目录到webapps目录下
cp -r webapps.dist/* webapps
现在我就想用想在的容器当做镜像提交
docker commit -m="tomcat add webapps" -a="youngj" 885a68576f0a tomcat-youngj:2.0
如果数据都存在容器中,那么我把容器删除,所有的数据将全部丢失!需求:数据可以持久化
如:MySQL数据可以存储在本地!
容器之间可以有一个数据共享技术,Docker容器产生的数据同步到本地!
这就是卷技术!目录的挂载,将我们容器的目录挂载到Linux上面!
总结:容器的持久化和同步操作!容器间也是可以数据共享的
docker run -it -v 主机目录:容器内目录
测试挂载
docker run -it -v /home/ceshi:/home centos /bin/bash
# 启动起来后通过inspect 容器ID 查看
测试数据同步
docker pull mysql:5.7
启动
-d 后台启动 -p 3310:3306 将公网端口3310与容器3306端口打通
-v 将宿主机/home/data/mysql/conf与容器/etc/mysql/conf.d共享(MySQL配置),
宿主机/home/data/mysql/data与容器/var/lib/mysql共享(MySQL数据)
-e 环境配置
docker run -d -p 3310:3306 \
-v /home/data/mysql/conf:/etc/mysql/conf.d \
-v /home/data/mysql/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name mysql-youngj mysql:5.7
测试数据是否同步到本地
# 容器中创建数据库
create database youngjdb;
查看本地/home/data/mysql/data中是否有youngjdb
匿名挂载
docker run -d -P --name nginx01 -v /etc/nginx nginx
# -v 只指定了容器内部的地址 没有指定外部的地址
docker volume ls
这种就是匿名挂载
具名挂载
docker run -d -P --name nginx01 -v juming-nginx:/etc/nginx nginx
# -v 卷名:容器内路径 指定了卷名juming-nginx
查看卷目录
docker inspect juming-nginx
总结:
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载
拓展:
docker run -d -P --name nginx01 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx01 -v juming-nginx:/etc/nginx:rw nginx
ro readonly #只读,只能从宿主机操作
rw readwrite #可读可写
DockerFile就是构建docker镜像的构建文件(命令脚本),通过这个脚本可以生成镜像,镜像是一层层的,脚本是一个个的命令,每个命令都是一层。
FROM centos
VOLUME ["volume01","youngj"]
CMD echo "----end-----"
CMD /bin/bash
执行脚本
docker build -f dockerfile1 -t youngj/centos .
查看镜像
运行
docker run -it 297ad69c511a /bin/bash
进入youngj文件夹,创建一个contener.txt文件
通过docker inspect 容器ID命令查看卷挂载的目录
进入目录查看文件是否生成成功
通过我们自己构建的镜像,启动3个,进行测试
docker run -it --name docker01 youngj/centos
再启动一个
docker run -it --name docker02 --volumes-from docker01 youngj/centos
#--volumes-from 实现了数据同步,相当于继承docker01
进入youngj文件夹,创建docker02.txt文件,再去docker01容器查看是否同步成功
在docker01容器中发现docker02.txt同步成功!
再新建一个docker03容器
docker run -it --name docker03 --volumes-from docker01 youngj/centos
再新建docker03.txt,发现docker01、docker02中同步成功!
删除docker01容器,查看docker02、docker03容器中docker01.txt文件是否存在
经测试,数据依然存在!
删除所有镜像、容器
docker rm -f $(docker ps -aq) # 删除所有容器
docker rmi -f $(docker images -aq) # 删除所有镜像
查看网卡信息
ip addr
docker 容器与容器之间是如何网络访问的?
# 下载Tomcat镜像
docker run -d -P --name tomcat01 tomcat
# 查看容器内网络地址, 发现eth0是分配的网卡,172.17.0.3是容器的地址
docker exec -it tomcat01 ip addr
[root@hecs-x-medium-2-linux-20200615101353 logs]# docker exec -it tomcat01 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
36583: eth0@if36584: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 经测试,宿主机是可以ping通容器的
原理
每启动一个docker容器,docker就会给容器分配一个IP,只要我们安装了docker就会有一个默认的网卡docker0,使用的是桥接模式,veth-pair技术。
再来看网卡信息 ip addr, 正好对应容器内网卡信息
再启动一个Tomcat
docker run -d -P --name tomcat02 tomcat
查看 ip addr
再查看容器 ip addr
docker exec -it tomcat02 ip addr
我们发现,这个容器带来的网卡都是一对一对的,
veth-pair 就是一对虚拟设备接口,他们都是成对出现,一端连着协议,一端彼此相连,veth-pair充当于一个桥梁,连接各种网络设备
测试Tomcat02是否能够ping通Tomcat01
docker exec -it tomcat02 ping 172.17.0.3
结论: Tomcat01 和 Tomcat02是公用的一个路由器,docker0,左右的容器在不指定网络的情况下,都是docker0来路由的,docker会给我们分配一个默认的可用IP!
Docker 使用的是Linux桥接,如下图
思考一个场景,我们编写了一个微服务,比如mysql的连接地址为:database.url=ip:port,数据库IP换掉了,我们想不重启解决这个问题,可以通过名字访问容器
# Tomcat02 ping Tomcat01时,提示tomcat01: Name or service not known,怎么解决呢?
docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known
#使用 --link
#再启动一个tomcat03
[root@hecs-x-medium-2-linux-20200615101353 logs]# docker run -d -P --name tomcat03 --link tomcat02 tomcat
5b369c8cf0dd227306f0ac3a32a7f0f06d17b20da4bd04a40cc58cecdde72e28
[root@hecs-x-medium-2-linux-20200615101353 logs]# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.4) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.4): icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from tomcat02 (172.17.0.4): icmp_seq=2 ttl=64 time=0.058 ms
64 bytes from tomcat02 (172.17.0.4): icmp_seq=3 ttl=64 time=0.050 ms
# 我们发现tomcat03是可以ping通Tomcat02的,那么反过来可以吗?
docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known
# 反过来是不可以的,其实tomcat3就是在本地配置了tomcat02的配置
docker exec -it tomcat03 cat /etc/hosts
[root@hecs-x-medium-2-linux-20200615101353 logs]# docker exec -it tomcat03 cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.4 tomcat02 53c7169fc50f
172.17.0.5 5b369c8cf0dd
# --link就是在hosts中增加了172.17.0.4 tomcat02 53c7169fc50f
# 我们现在已经不推荐这种方式!!!
docker0不支持自定义网络!
查看所有的docker网络
docker network ls
网络模式
bridge:桥接 docker(默认,自己创建也使用bridge模式)
none:不配置网络
host:和宿主机共享网络
container:容器网络连通(用的少)
测试
# 我们直接启动的命令 --net bridge, 而这个就是我们的docker0
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat01 --net bridge tomcat
#docker0的特点:默认,域名不能访问,可以通过--link打通,但是太麻烦,不推荐!
#我们可以自定义一个网络
[root@hecs-x-medium-2-linux-20200615101353 logs]# docker network --help
Usage: docker network COMMAND
Manage networks
Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks
# --driver bridge
# --subnet 192.168.0.0/16 (16代表255*255个端口=65535) 192.168.0.2 到 192.168.255.255
# --gateway 192.168.0.1
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
dc07b32aa00eb41f03603c5b46147dd890dcd02c9598b0013d062fd3cea7c75a
[root@hecs-x-medium-2-linux-20200615101353 logs]# docker network ls
NETWORK ID NAME DRIVER SCOPE
e6ff23e009d3 bridge bridge local
798d3792b63c host host local
dc07b32aa00e mynet bridge local
f6279634a0e8 none null local
我们自己的网络就建好了
启动两个tomcat,测试是否互通
# 先启动 tomcat-net-01
docker run -d -P --name tomcat-net-01 --net mynet tomcat
# 再启动 tomcat-net-02
docker run -d -P --name tomcat-net-02 --net mynet tomcat
# --net 使用我们自己创建的网络
docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.047 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.048 ms
# 反向测试
docker exec -it tomcat-net-02 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.028 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.049 ms
我们自定义的网络,docker都已经帮我们维护好了对应关系,推荐这样使用!
好处:
mysql:不同集群使用不同网络,保证集群安全、健康
redis:不同集群使用不同网络,保证集群安全、健康
如果此时我想tomcat01和tomcat-net-01互通,也就是和mynet打通,怎么操作?
docker network connect --help
Usage: docker network connect [OPTIONS] NETWORK CONTAINER
Connect a container to a network
Options:
--alias strings Add network-scoped alias for the container
--driver-opt strings driver options for the network
--ip string IPv4 address (e.g., 172.30.100.104)
--ip6 string IPv6 address (e.g., 2001:db8::33)
--link list Add link to another container
--link-local-ip strings Add a link-local address for the container
docker network connect mynet tomcat01 #将mynet 和 tomcat01打通
[root@hecs-x-medium-2-linux-20200615101353 logs]# docker exec -it tomcat01 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.059 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.058 ms
查看mynet详情
docker network inspect mynet
发现mynet Containers中多了一个tomcat01容器!
docker通过一个容器 两个IP方式,如:阿里云公网IP和私网IP,将两个容器打通!
总结:假如我要跨网络操作别人,就需要用docker network connect连接!
# 创建网卡
docker network create redis --subnet 172.38.0.0/16
# 使用脚本创建6个配置文件
for port in $(seq 1 6); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
# 启动redis-1
docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
-v /mydata/redis/node-1/data:/data \
-v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
# 启动redis-2
docker run -p 6372:6379 -p 16372:16379 --name redis-2 \
-v /mydata/redis/node-2/data:/data \
-v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
# 启动redis-3
docker run -p 6373:6379 -p 16373:16379 --name redis-3 \
-v /mydata/redis/node-3/data:/data \
-v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
# 启动redis-4
docker run -p 6374:6379 -p 16374:16379 --name redis-4 \
-v /mydata/redis/node-4/data:/data \
-v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
# 启动redis-5
docker run -p 6375:6379 -p 16375:16379 --name redis-5 \
-v /mydata/redis/node-5/data:/data \
-v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
# 启动redis-6
docker run -p 6376:6379 -p 16376:16379 --name redis-6 \
-v /mydata/redis/node-6/data:/data \
-v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
# 创建集群
# 随便进入一个容器
docker exec -it redis-1 /bin/sh
redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.38.0.15:6379 to 172.38.0.11:6379
Adding replica 172.38.0.16:6379 to 172.38.0.12:6379
Adding replica 172.38.0.14:6379 to 172.38.0.13:6379
M: 1f7c20e84a30b48a98e196bfaa2a8229321614aa 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
M: 7aeb822b2771d4f2ceafef662684486ec6b7db70 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
M: 6c8d11c99dc37ba11bbe23465a578ac25cefae21 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
S: a165daef5112eccf35afba2e9f0df60eb68a13ef 172.38.0.14:6379
replicates 6c8d11c99dc37ba11bbe23465a578ac25cefae21
S: 6bd4754e3c2cfc68dc7d34167292c1af4c1a5853 172.38.0.15:6379
replicates 1f7c20e84a30b48a98e196bfaa2a8229321614aa
S: 7b81af71af3cbe4f2340b2146f4d8a78cc3cb143 172.38.0.16:6379
replicates 7aeb822b2771d4f2ceafef662684486ec6b7db70
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
...
>>> Performing Cluster Check (using node 172.38.0.11:6379)
M: 1f7c20e84a30b48a98e196bfaa2a8229321614aa 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 6bd4754e3c2cfc68dc7d34167292c1af4c1a5853 172.38.0.15:6379
slots: (0 slots) slave
replicates 1f7c20e84a30b48a98e196bfaa2a8229321614aa
M: 7aeb822b2771d4f2ceafef662684486ec6b7db70 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: a165daef5112eccf35afba2e9f0df60eb68a13ef 172.38.0.14:6379
slots: (0 slots) slave
replicates 6c8d11c99dc37ba11bbe23465a578ac25cefae21
S: 7b81af71af3cbe4f2340b2146f4d8a78cc3cb143 172.38.0.16:6379
slots: (0 slots) slave
replicates 7aeb822b2771d4f2ceafef662684486ec6b7db70
M: 6c8d11c99dc37ba11bbe23465a578ac25cefae21 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
测试主从,当主挂了之后,从是否会成为主
/data # redis-cli -c
# 查看集群信息
172.38.0.13:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:3
cluster_stats_messages_ping_sent:568
cluster_stats_messages_pong_sent:568
cluster_stats_messages_meet_sent:3
cluster_stats_messages_sent:1139
cluster_stats_messages_ping_received:566
cluster_stats_messages_pong_received:571
cluster_stats_messages_meet_received:2
cluster_stats_messages_received:1139
#查看节点信息
172.38.0.13:6379> CLUSTER nodes
7b81af71af3cbe4f2340b2146f4d8a78cc3cb143 172.38.0.16:6379@16379 slave 7aeb822b2771d4f2ceafef662684486ec6b7db70 0 1600681888561 6 connected
1f7c20e84a30b48a98e196bfaa2a8229321614aa 172.38.0.11:6379@16379 master - 0 1600681887000 1 connected 0-5460
6c8d11c99dc37ba11bbe23465a578ac25cefae21 172.38.0.13:6379@16379 myself,master - 0 1600681888000 3 connected 10923-16383
a165daef5112eccf35afba2e9f0df60eb68a13ef 172.38.0.14:6379@16379 slave 6c8d11c99dc37ba11bbe23465a578ac25cefae21 0 1600681887057 4 connected
7aeb822b2771d4f2ceafef662684486ec6b7db70 172.38.0.12:6379@16379 master - 0 1600681888561 2 connected 5461-10922
6bd4754e3c2cfc68dc7d34167292c1af4c1a5853 172.38.0.15:6379@16379 slave 1f7c20e84a30b48a98e196bfaa2a8229321614aa 0 1600681888061 5 connected
# 随便存一个值,发现存在172.38.0.13:6379
127.0.0.1:6379> set a b
-> Redirected to slot [15495] located at 172.38.0.13:6379
OK
# 当172.38.0.13这台服务挂了之后,测试是否能查询到值
# 停掉redis-3
docker stop redis-3
# 重新查询
get a
-> Redirected to slot [15495] located at 172.38.0.14:6379
"b"
# 重新查看节点状态,发现172.38.0.13:6379 fail, 172.38.0.14已经成为了master
172.38.0.14:6379> CLUSTER nodes
7aeb822b2771d4f2ceafef662684486ec6b7db70 172.38.0.12:6379@16379 master - 0 1600682270008 2 connected 5461-10922
6c8d11c99dc37ba11bbe23465a578ac25cefae21 172.38.0.13:6379@16379 master,fail - 1600682209785 1600682208000 3 connected
1f7c20e84a30b48a98e196bfaa2a8229321614aa 172.38.0.11:6379@16379 master - 0 1600682271510 1 connected 0-5460
7b81af71af3cbe4f2340b2146f4d8a78cc3cb143 172.38.0.16:6379@16379 slave 7aeb822b2771d4f2ceafef662684486ec6b7db70 0 1600682272011 2 connected
6bd4754e3c2cfc68dc7d34167292c1af4c1a5853 172.38.0.15:6379@16379 slave 1f7c20e84a30b48a98e196bfaa2a8229321614aa 0 1600682270000 5 connected
a165daef5112eccf35afba2e9f0df60eb68a13ef 172.38.0.14:6379@16379 myself,master - 0 1600682271000 7 connected 10923-16383
dockerFile是用来构建docker镜像的文件。它就是命令脚本!
构建步骤:
1、编写一个dockerFile文件
2、docker build 构建成一个镜像
3、运行镜像
4、docker push 发布镜像(DockerHub、阿里云镜像仓库)
基础知识
1、每个关键字必须是大写字母
2、执行顺序是从上到下顺序执行
3、#表示注释
4、每一个指令都会创建提交一个新的镜像层,并提交!
dockerFile是面向开发的,以后发布项目就需要编写dockerFile。
DockerFile:构建文件,定义了一切步骤,源代码
DockerImages:通过DockerFile构建生成一个镜像,最终发布运行的产品
Docker容器:容器就是镜像运行起来提供服务
FROM #基础镜镜像,一切从这里开始构建
MAINTAINER #镜像是谁写的,姓名+邮箱
RUN #镜像构建的时候需要运行的命令
ADD #步骤: tomcat镜像,这个tomcat压缩包!添加内容
WORKDIR #镜像的工作目录
VOLUME #挂载的目录
EXPOSE #保留端口配置
CMD #指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT #指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD #当构建一个被继承DockerFile 这个时候就会运行ONBUILD 的指令。触发指令。
COPY #类似ADD,将我们文件拷贝到镜像中
ENV #构建的时候设置环境变量!
编写DockerFile文件
vim dockerfile-centos
# dockerfile内容如下:
FROM centos
MAINTAINER youngJ<[email protected]>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "----build success----"
CMD /bin/bash
构建镜像
docker build -f dockerfile-centos -t mycentos:0.1 .
# docker build -f 脚本路径 -t 镜像名:版本号 .
启动
docker run -it mycentos:0.1
测试是否含有vim命令
经测试,含有vim命令!
查看镜像历史构建信息
docker history 镜像ID
测试CMD命令和ENTRYPOINT的区别
# 编写dockerfile-cmd文件
FROM centos
CMD ["ls", "-a"]
# 构建镜像
docker build -f dockerfile-cmd -t dockerfilecmd:0.1 .
# 启动镜像
docker run dockerfilecmd:0.1
[root@hecs-x-medium-2-linux-20200615101353 dockerFile]# docker run dockerfilecmd:0.1
.
..
.dockerenv
bin
dev
etc
home
...
# 想追加一个指令 ls -al
docker run dockerfilecmd:0.1 -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"-l\": executable file not found in $PATH": unknown.
测试ENTRYPOINT命令
# 编写dockerfile-entrypoint文件
FROM centos
ENTRYPOINT ["ls", "-a"]
#构建镜像
docker build -f dockerfile-entrypoint -t dockerfile-entrypoint:0.1 .
#启动镜像
docker run dockerfile-entrypoint:0.1
[root@hecs-x-medium-2-linux-20200615101353 dockerFile]# docker run dockerfile-entrypoint:0.1
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
# 追加一个命令 -l 也就是 ls -al
docker run dockerfile-entrypoint:0.1 -l
[root@hecs-x-medium-2-linux-20200615101353 dockerFile]# docker run dockerfile-entrypoint:0.1 -l
total 56
drwxr-xr-x 1 root root 4096 Sep 18 09:30 .
drwxr-xr-x 1 root root 4096 Sep 18 09:30 ..
-rwxr-xr-x 1 root root 0 Sep 18 09:30 .dockerenv
lrwxrwxrwx 1 root root 7 May 11 2019 bin -> usr/bin
drwxr-xr-x 5 root root 340 Sep 18 09:30 dev
drwxr-xr-x 1 root root 4096 Sep 18 09:30 etc
drwxr-xr-x 2 root root 4096 May 11 2019 home
lrwxrwxrwx 1 root root 7 May 11 2019 lib -> usr/lib
lrwxrwxrwx 1 root root 9 May 11 2019 lib64 -> usr/lib64
...
FROM centos
MAINTAINER youngJ<[email protected]>
ADD jdk-8u251-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.38.tar.gz /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_251
ENV CLASSPATH $JAVA_HOME/lib/dt.jar;$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.38
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.38
ENV PATH $PATH;$JAVA_HOME/bin;$CATALINA_HOME/lib;$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.38/bin/startup.sh && tailf /usr/local/apache-tomcat-9.0.38/logs/catalina.out
build 镜像
docker build -f dockerfile -t mytomcat:2.0 .
启动
docker run -d -p 8080:8080 --name mytomcat -v /home/data/tomcat/test:/usr/local/apache-tomcat-9.0.38/webapps/test -v /home/data/tomcat/logs:/usr/local/apache-tomcat-9.0.38/logs mytomcat:2.0
测试目录是否同步成功
新建web.xml
mkdir WEB-INF
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
web-app>
新建index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
youngj
Hello World!
<%
System.out.println("你的 IP 地址 " + request.getRemoteAddr());
%>
注册并登陆
DockerHub官网
使用命令行登陆再提交
docker login --help
Options:
-p, --password string Password
--password-stdin Take the password from stdin
-u, --username string Username
docker login -u youngj
发布
# 发布我自己定义的tomcat2.0
docker push mytomcat:2.0
The push refers to repository [docker.io/library/mytomcat]
aa19e7b28c26: Preparing
a5f01137bfee: Preparing
336ebc8bd789: Preparing
291f6e44771a: Preparing
denied: requested access to the resource is denied # 被拒绝
#解决:增加一个tag
# docker tag 镜像ID 作者/镜像名称:版本
docker tag 4416171521d9 youngj/mytomcat:2.0
#REPOSITORY TAG IMAGE ID CREATED SIZE
#youngj/mytomcat 2.0 4416171521d9 About an hour ago 694MB
docker push youngj/mytomcat:2.0
[root@hecs-x-medium-2-linux-20200615101353 logs]# docker push youngj/mytomcat:2.0
The push refers to repository [docker.io/youngj/mytomcat]
aa19e7b28c26: Pushing [> ] 1.107MB/57.24MB
a5f01137bfee: Pushing [==============> ] 4.505MB/15.6MB
336ebc8bd789: Pushing [> ] 2.188MB/405.8MB
291f6e44771a: Pushing [> ] 2.725MB/215.1MB
登陆阿里云官网
阿里云官网
找到容器镜像服务
创建命名空间
查看详情
登陆
docker login --username=用户名 registry.cn-hangzhou.aliyuncs.com
打个标签
docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/youngj/youngj:[镜像版本号]
上传
docker push registry.cn-hangzhou.aliyuncs.com/youngj/mytomcat:2.0
The push refers to repository [registry.cn-hangzhou.aliyuncs.com/youngj/mytomcat]
aa19e7b28c26: Pushing [=> ] 2.221MB/57.24MB
a5f01137bfee: Pushing [==> ] 703.5kB/15.6MB
336ebc8bd789: Pushing [> ] 1.075MB/405.8MB
291f6e44771a: Pushing [> ] 1.082MB/215.1MB
新建springboot项目
新建controller
@RestController
public class TestController {
@RequestMapping("/hello")
public String hello() {
return "hello! youngJ";
}
}
新建Dockerfile
# 基础镜像 Java8
FROM java:8
# 把所有的jar 放到app.jar中
COPY *.jar /app.jar
# 指定端口8080
CMD ["--server.port=8080"]
# 对外暴露端口8080
EXPOSE 8080
# 执行命令 java -jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
构建镜像
将springboot项目package打包与Dockerfile文件放到服务器
docker build -f Dockerfile -t docker-idea:0.0.1 .
运行
docker run -d -P --name idea-docker docker-idea:0.0.1
查看端口
[root@hecs-x-medium-2-linux-20200615101353 docker-idea]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
83ec9d1c32fd docker-idea:0.0.1 "java -jar /app.jar …" 15 seconds ago Up 14 seconds 0.0.0.0:32778->8080/tcp idea-docker
请求接口
[root@hecs-x-medium-2-linux-20200615101353 docker-idea]# curl localhost:32778/hello
hello! youngJ
下期预告:
Docker进阶版 :Docker compose、Docker swarm、k8s等实战
敬请关注公众号