下载
docker 命令
帮助
# 查看 docker 命令的 options 和 command
$ docker --help
# 查看具体 command 的使用方式
$ docker command --help
查看 docker 容器信息
# 查看 docker 所有容器和镜像的数量、docker 使用的执行驱动和存储驱动以及 docker 的基本配置。
# 可以通过这个命令查看 docker 是否安装成功
$ docker info
# 查看正在运行的容器
$ docker ps
# 查看所有的容器,包括已经停止的容器
$ docker ps -a
# 查看最后 x 个容器,不论容器是否停止
$ docker ps -n 3
# 查看容器内的进程,在此约定 CONTAINER 代表 containerId 或者 containerName
$ docker top CONTAINER
# 查看一到多个容器的统计信息,例如:CPU、内存、网络I/O、存储I/O的性能和指标,常用于快速监控
$ docker status CONTAINER1 CONTAINER2 CONTAINER2 ...
# 查看本地镜像
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.sensetime.com/plat-bigdata/superset 0.37.2_s1 92672dae0eaf 34 minutes ago 2.62GB
registry.sensetime.com/plat-bigdata/superset latest 92672dae0eaf 34 minutes ago 2.62GB
...
# Get details info of image
$ docker inspect IMAGE
$ docker inspect registry.sensetime.com/plat-bigdata/superset:latest
[
{
"Id": "sha256:92672dae0eaf918407418ec12c9a617bf4547b128f1b557a838b945923bfc9ff",
"RepoTags": [
"registry.sensetime.com/plat-bigdata/superset:0.37.2_s1",
"registry.sensetime.com/plat-bigdata/superset:latest"
],
"RepoDigests": [
"registry.sensetime.com/plat-bigdata/superset@sha256:e6999e708c785faf2a814a478fb2c60a9a4a2ef44be3de8e49a400fb56a1531f"
],
"Parent": "sha256:b942048c7428c42401b5a6e6e8f91bf6a80bb25ea4ac260d099ed5f0a0504c24",
"Comment": "",
"Created": "2020-11-06T07:54:27.712457746Z",
"Container": "be51ad23bcf8513571d47acb7553976d93dea510a9485c9f6bcae349ee920b49",
"ContainerConfig": {
"Hostname": "be51ad23bcf8",
"Domainname": "",
"User": "superset",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"8080/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"LANG=C.UTF-8",
"GPG_KEY=0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D",
"PYTHON_VERSION=3.6.9",
"PYTHON_PIP_VERSION=19.3.1",
"PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/ffe826207a010164265d9cc807978e3604d18ca0/get-pip.py",
"PYTHON_GET_PIP_SHA256=b86f36cc4345ae87bfd4f10ef6b2dbfa7a872fbff70608a1e43944d283fd0eee",
"LC_ALL=C.UTF-8",
"FLASK_ENV=production",
"FLASK_APP=superset.app:create_app()",
"PYTHONPATH=/app/pythonpath",
"SUPERSET_HOME=/app/superset_home",
"SUPERSET_PORT=8080"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"USER superset"
],
"Healthcheck": {
"Test": [
"CMD",
"curl",
"-f",
"http://localhost:8088/health"
]
},
"Image": "sha256:b942048c7428c42401b5a6e6e8f91bf6a80bb25ea4ac260d099ed5f0a0504c24",
"Volumes": null,
"WorkingDir": "/app",
"Entrypoint": [
"/usr/bin/docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {}
},
"DockerVersion": "19.03.11",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "superset",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"8080/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"LANG=C.UTF-8",
"GPG_KEY=0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D",
"PYTHON_VERSION=3.6.9",
"PYTHON_PIP_VERSION=19.3.1",
"PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/ffe826207a010164265d9cc807978e3604d18ca0/get-pip.py",
"PYTHON_GET_PIP_SHA256=b86f36cc4345ae87bfd4f10ef6b2dbfa7a872fbff70608a1e43944d283fd0eee",
"LC_ALL=C.UTF-8",
"FLASK_ENV=production",
"FLASK_APP=superset.app:create_app()",
"PYTHONPATH=/app/pythonpath",
"SUPERSET_HOME=/app/superset_home",
"SUPERSET_PORT=8080"
],
"Cmd": null,
"Healthcheck": {
"Test": [
"CMD",
"curl",
"-f",
"http://localhost:8088/health"
]
},
"Image": "sha256:b942048c7428c42401b5a6e6e8f91bf6a80bb25ea4ac260d099ed5f0a0504c24",
"Volumes": null,
"WorkingDir": "/app",
"Entrypoint": [
"/usr/bin/docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": null
},
"Architecture": "amd64",
"Os": "linux",
"Size": 2615117997,
"VirtualSize": 2615117997,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/dae93afb24535a09a2633ccccdd4fc34fe667e8db47ac82e0c0643fb729efab3/diff:/var/lib/docker/overlay2/25a7eb0773d349ee18eab4d23b38cca33ff862e6a6ee1db72004c69b2b77fdcc/diff:/var/lib/docker/overlay2/d149dd257bd193de2637f3aa9a2dfc77d1908acef089560990abcc4a0f3c2e67/diff:/var/lib/docker/overlay2/2a454d8f330ad35954e014f3b9722c7d4506f858db3b5d6102c6b095ba24fa87/diff:/var/lib/docker/overlay2/570dff4681ee1ee230a3661ae70816892b96972c4a497473cba832efce8eb727/diff:/var/lib/docker/overlay2/679c2adcc841361403fddd482e92bead297ded275cec45af445977f95c7aa92f/diff:/var/lib/docker/overlay2/dd34be49c0457f4717ce88affdc36c8b8838e506c7f64368265df42019f21dc1/diff:/var/lib/docker/overlay2/38d6f04e8fcc84ebd5ca9247c438394117b95c69631dc7761d86b041a8530053/diff:/var/lib/docker/overlay2/1ef1bab72956d9af4a774e827d35c90668f7fc3fad8e802e07baac4ac1f4d47e/diff:/var/lib/docker/overlay2/fbba98d71698f8fc95be8bd15effd5579ba42fa3330048ad3a7ae85d7200f99e/diff:/var/lib/docker/overlay2/93a1b31e0f84d7e9b13f6218a81ad58655936e9bd19c0576921aa837e737536a/diff:/var/lib/docker/overlay2/c5199189f51148f487c8f7d29bba9b1aa4705aa2a017aa4619457e294a007b1d/diff:/var/lib/docker/overlay2/89eca378b96f662c42da93436ff37ec91234884a519964f7cacc740700ecbe5f/diff:/var/lib/docker/overlay2/b1d2cecc8e85de533dc679f3e8194dfd90d858a650dab3fc3a75ca39e062f4a0/diff:/var/lib/docker/overlay2/19ece21c2506e439b14591b5f7f29450f236161bd7389d1be5981060e3030aa5/diff:/var/lib/docker/overlay2/9bd488d211631c1c06b9524162475b33701ba8688f23b9271691eeb7512061a1/diff:/var/lib/docker/overlay2/7483f09a6684fd64add52eb276883b5ed08d0714262ba7a068fc894bde11cce1/diff:/var/lib/docker/overlay2/7c1c694b85fced9dd6dd4e33f47435e164785418751d97fcd10e4b8351ea591b/diff:/var/lib/docker/overlay2/2e4ab11e66a8995dcc1ed3537a923cbb088be86c21f5741b09948024057e198f/diff",
"MergedDir": "/var/lib/docker/overlay2/3aa192a3a64868758cddffe02f179d25c15a984d3dec4558680851c98fc5cbea/merged",
"UpperDir": "/var/lib/docker/overlay2/3aa192a3a64868758cddffe02f179d25c15a984d3dec4558680851c98fc5cbea/diff",
"WorkDir": "/var/lib/docker/overlay2/3aa192a3a64868758cddffe02f179d25c15a984d3dec4558680851c98fc5cbea/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:f2b4f0674ba3e6119088fe8a98c7921ed850c48d4d76e8caecd7f3d57721b4cb",
"sha256:7f9bf938b0531c93cc0d860e72aac23093189889d89604ce24b95197435b76cf",
"sha256:423d63eb4a274765e80c67db008e5cb9318b717c3a57790b75b53d3440a9f3e0",
"sha256:bee1c15bf7e859fe57266ca0739533b44950a5e03333e751e05de04e0e6cf7d3",
"sha256:9437609235f034beed771825bfb42b48bdec58a55fd1e89588750c426bf55c4e",
"sha256:852a1bb5386cb2e36b22d11db7357b241d540e738cc467d9ff5f351d9dd069ce",
"sha256:d20676915161118d1c96e60e17b4a0e90cba8f8e93de6681650ee07cb42a42c8",
"sha256:7ebccfde7bb7f4114744d494eb182e3f2d92ce99aa7bff266b9526416e3974bf",
"sha256:9ab20c4343be22704a3dc4309659908ae37b02ed6e6c55598b3aabc969adc19f",
"sha256:d89df28dedc01502ab1097b6162b06b2e6fa5ce6b4b6bca40fd412b8ddff2c50",
"sha256:da25db0a968977504450be8235a444d923c79b7282546395c2dbce8c684ef20a",
"sha256:4e12eeda71b9563fd90eb603a5ce3310aaa5a0dfc4bc2abaeaed0011c7526c9e",
"sha256:cfc0f58b5d92bf64dfc03e05d7a88a395e3b65a8064c679238e7129a4af086d4",
"sha256:a7d0b89428048c8e9da0e3d97097ad828bed3c8de1e8e99392224aec13f1abaf",
"sha256:7b06caba74db060de2373b6e029c3dd48a7f2da711908666a03d66f4ba22a08a",
"sha256:ed66bd4e974d2cc9f7af40c010055ee0d146acaebe29c361496120af147c05ad",
"sha256:a86a366a6e2a8c4eadac5b82871ac6f29bf85d4eda3e58b549d2a7d3517d7cbc",
"sha256:52bfba46cfd07923d9fa07b8a1abaefe4b0e0cf49cf768e26abf439ecdf1a09b",
"sha256:83df23365cd178d098dd779b78e2468b3ce16b4f20fbba583ff8beebd4687722",
"sha256:b35d1d4b4affd95d575af6434da6d86bc270e48cac45e997a13974991e53bfea"
]
},
"Metadata": {
"LastTagTime": "2020-11-06T15:54:33.059716673+08:00"
}
}
]
# 对容器进行详细的检查,然后返回 json 格式的配置信息,如:名称、命令、网络配置以及很多有用的数据
$ docker inspect CONTAINER
# 可以使用 -f 或者 --format 选定某项结果,其实这个参数支持完整的 GO 语言模版
$ docker inspect --format='' CONTAINER
docker 创建/启动、停止、删除容器
# 创建/启动容器
$ docker run --help
# Usage
$ docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
# run 创建、启动一个新的容器
# -i 保证容器中STDIN是开启的,尽管我们没有 attach 到容器中
# -t 为创建的容器分配一个伪 tty 终端
# -i 和 -t 两个参数同时存在,新建的容器才能提供一个交互式 shell
# /bin/bash 执行容器中的 shell
$ docker run -it ubuntu /bin/bash
# 其中 fd2dcda313a4 是容器 id,(hostname)
root@fd2dcda313a4:/#
# 退出 shell,这样容器也会跟着停止
root@fd2dcda313a4:/# exit
# 创建守护式容器(daemonized container)
# -d docker 会将容器放到后台运行,执行完后,他不会像 -it 一样将主机的控制台
# 附着到新的shell会话上,而是仅仅返回了一个容器ID
$ docker run -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"
# 为容器命名,这样就不一定非要用容器id去访问容器了,但是容器的命名必须是唯一的
$ docker run --name test_container -i -t centos /bin/bash
# 启动容器并暴露多个端口 -p, --expose
$ docker run -p <host_port1>:<container_port1> -p <host_port2>:<container_port2> IMAGE
# 附着到正在运行容器的会话,可能需要回车才能进入会话
$ docker attach CONTAINER
# 在容器内部运行额外的进程(docker 1.3+)
# 例如进入容器内 shell 会话
$ docker exec -it CONTAINER /bin/bash
# 启动一个新的后台任务
$ docekr exec -d CONTAINER touch /etc/new-config-file
# 停止守护式容器,向 docker 容器进程发送 SIGTERM 信号
$ docker stop CONTAINER
# 如果想快速停止某个容器,还可以直接向 docker 容器进程发送 SIGKILL 信号
$ docker kill CONTAINER
# 重新启动已经停止的 container,docekr 重启的时候会沿用 docker run 时指定的参数来运行。
$ docker start CONTAINER
# 自动重启容器 --restart
# --restart=always 无论容器的退出代码是什么,docker 都会重新启动该容器
$ docker run --restart=always -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"
# --restart=on-failure 只有当容器的退出代码为非0值的时候才会自动重启,除此之外还可以接收一个重启次数的参数
$ docker run --restart=on-failure:5 -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"
# 删除容器(从这里开始,CONTAINER 代表容器ID/容器名)
$ docker rm CONTAINER
# 删除镜像
$ docker rmi IMAGE_ID
# 如果镜像被多个库引用(IMAGE_ID 相同),只会 Untag Image,而非删除镜像
$ docker rmi IMAGE_NAME:TAG
docker 容器日志
# 获取 docker 内部最新的日志
$ docker logs CONTAINER
# -f 滚动输出日志,类似 tail -f
# --tail 10 返回最后10条日志,每次
$ docker logs -f --tail 10 CONTAINER
# docker1.6起,可以控制 docekr 所用的日志驱动,在 docker run 时,使用 --log-driver 进行控制
# --log-driver 默认 json-file 还有其他可用选项,如:
# syslog 该选项禁用 docker logs 命令,并将所有容器的日志输出都重定向到 syslog
# none 该选项也会禁用所有容器中的日志,导致 docker logs 不可用
# 1.8 之后还有 fluentd 日志轮转驱动等等
$ docker run --log-driver="syslog" -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"
# 容器最多有三个日志文件,每个日志文件最大500m
$ docker run --log-driver="json-file" --log-opt max-file=3 --log-opt max-size=500m -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"
使用 Dockerfile 构建镜像
Context
通过Dockerfile
的和docker build
去构建镜像更具备可重复性、透明性以及幂等性,不推荐通过docker commit
构建镜像。
# 创建一个目录用来保存 Dockerfile
$ mkdir contextDir
$ cd contextDir
$ touch Dockerfile
这个目录就是我们的构建环境(context/build context),docker 会把contextDir
中的所有文件/文件夹保存到类似/var/lib/docker/tmp/docker-builder833199817
目录下,这样在构建镜像的时候就可以直接访问,而对于不在上下文环境中的文件,docker 是访问不到的。
编写 Dockerfile
- Dockerfile reference,其中包含了各种命令的使用方法
$ vim Dockerfile
# 指定 base image
FROM ubuntu:14.04
# 指定镜像作者和电子邮件
MAINTAINER zhangqiang "[email protected]"
# RUN指令会在当前镜像中运行指定的命令
RUN apt-get update && apt-get install -y nginx
RUN echo 'Hi, I am in your container' \
>/usr/share/nginx/html/index.html
# 该容器内的应用程序将使用容器的指定端口,但这并不意味着你可以访问容器中运行服务的端口。
# 可以指定多个 EXPOSE 向外部公开多个端口
EXPOSE 80
Dockerfile
是由一系列指令和参数组成的。每条指令,如FROM
都必须为大写字母,且后面要跟随一个参数。Dockerfile中的指令会按顺序从上到下执行,所以应该根据需要合理安排指令的顺序。
每条指令都会创建一个新的镜像层并commit。docker 执行 Dockerfile 的流程如下:
- Docker 从基础镜像运行一个容器(因此第一条指令必须是 FROM)
- 每执行一条指令,对容器作出修改,并执行类似 docker commit 的操作,提交一个新的镜像层。
- Docker 基于刚提交的镜像运行一个新容器
- 执行下一条指令,直到所有指令都执行完毕。
从上面可以看出,即便某条指令执行失败了,也会得到一个可以使用的镜像(只要有一条指令执行成功),这样就可以基于镜像启动一个具备交互功能的容器进行调试,查找用户指令失败的原因。
出于安全原因,docker 并不会自动打开运行服务的端口,而是需要用户在使用docker run
运行容器的时候指定需要打开的端口。
Shell vs Exec
对于 Docker RUN
、ENRTYPOINT
或者CMD
有两种形式的写法:
- Shell Form
RUN "apt-get intsall -y nginx"
- Exec Form
# 这种方式,需要使用一个数组来指定要运行的命令和传递给该命令的每个参数。 RUN ["apt-get", "intsall", "-y", "nginx"]
默认情况下,RUN
指令会在Shell
里使用命令包装器/bin/sh -c
来执行,如果是在一个不支持Shell
的平台上运行或者不希望在Shell
中运行(比如避免Shell
字符串篡改),也可以使用Exec
格式的RUN
指令,Exec
形式, 与Shell
形式不同,Exec
形式不会调用/bin/sh -c
,这意味着正常的Shell
处理不会发生。例如,ENTRYPOINT [ "echo", "$HOME" ]
不会在$HOME
上进行变量替换。如果想要进行Shell
处理,可以使用Shell
形式直接执行命令,例如:ENTRYPOINT echo "$HOME"
,而ENTRYPOINT ["java", "-jar", "app.jar", "--spring.profiles.active=$RUN_ENV"]
不会进行$RUN_ENV
的变量替换。不过把命令写在脚本里面,比如ENTRYPOINT ["./entrypoint.sh"]
,这样就可以进行变量替换了。
CMD vs ENTRYPONIT
简单理解就是CMD
可以被重写,而Entrypoint
是不可以被重写的,除非启动 Container 的时候添加--entrypoint
。所以一般是把不希望修改的executable
命令写到Entrypoint
,把可以修改的默认参数写到CMD
,这样就更容易其他人在docker run
的时候动态修改默认参数,但是不能修改执行命令。
Note: 当 Dockerfile 中没有
CMD
、ENTRYPONIT
时,启动容器会报错。对于 KubernetesK8s Command <=> Docker Entrypoint
,K8s Args <=> Docker Cmd
构建镜像
执行docker build
命令时,Dockerfile中的所有指令都会被执行并且提交,并且在该命令成功结束后返回一个新镜像。
$ cd contextDir
# -t 指定仓库和镜像名
# 也可以在创建镜像的过程中指定标签,语法为"镜像名:标签",如果不指定标签则默认为latest
# . 表示上下文环境是当前目录,也可以用绝对路径,docker 默认在指定的 contextDir 的
# 根目录下查找 dockerfile
$ docker build -t="myrepository/myimage:v1" .
Sending build context to Docker daemon 2.048kB
Step 1/5 : FROM ubuntu:14.04
14.04: Pulling from library/ubuntu
72c01b436656: Pull complete
65584f5f70ee: Pull complete
dc9874b52952: Pull complete
86656bbaa6fd: Pull complete
7fe6916ab382: Pull complete
Digest: sha256:cb96ec8eb632c873d5130053cf5e2548234e5275d8115a39394289d96c9963a6
Status: Downloaded newer image for ubuntu:14.04
---> c32fae490809
Step 2/5 : MAINTAINER zhangqiang "[email protected]"
---> Running in 4f9718652c27
Removing intermediate container 4f9718652c27
---> 7b453722693d
Step 3/5 : RUN apt-get update && apt-get install -y nginx
---> Running in 5cff91f7fd39
Ign http://archive.ubuntu.com trusty InRelease
Get:1 http://security.ubuntu.com trusty-security InRelease [65.9 kB]
Get:2 http://archive.ubuntu.com trusty-updates InRelease [65.9 kB]
Get:3 http://security.ubuntu.com trusty-security/universe Sources [98.6 kB]
...
...
...
Removing intermediate container 5cff91f7fd39
---> 342eafd8c1c3
Step 4/5 : RUN echo 'Hi, I am in your container' >/usr/share/nginx/html/index.html
---> Running in f68817f0ba78
Removing intermediate container f68817f0ba78
---> b7a7edcb3c66
Step 5/5 : EXPOSE 80
---> Running in 12d9168d6c2a
Removing intermediate container 12d9168d6c2a
---> c208ff11437a
Successfully built c208ff11437a
Successfully tagged myrepository/myimage:v1
# 可以同时指定多个标签
$ docker build -t="myrepository/myimage:v1" -t "myrepository/myimage:latest" .
# -f 指定 Dockerfile,这里可以起其他的名字,但是必须在上下文环境中
$ docker build -t="myrepository/myimage:v1" -f ./path/other.dockerfile .
# 也可以指定一个 Git 地址(假设Dockerfile在项目的根目录)作为 contextDir,如
$ docker build -t="myrepository/myimage:v1" [email protected]:myrepository/contextDir
如果构建上下文的根目录下存在.dockerignore
命名的文件,每一行是一个匹配项(Go语言的filepath),匹配到的文件不会上传到Docker daemon中。与.gitignore
比较类似。
Dockerfile 和构建缓存
docker 的每一步的构建过程都会将结果提交为镜像,它会将之前的镜像层视作缓存,即最后一个成功的镜像。如果在step4出错,修改Dockerfile之后再次构建会直接从step4开始。
有时候需要确保构建的过程不能使用缓存,例如已经缓存到了step3。即apt-get update
,如果使用缓存,那么docker就不会更新apt的缓存了。可以使用docker run
的--no-cache
忽略Dockerfile的构建缓存
$ docker build -t="myrepository/myimage:v1" --no-cache .
构建缓存的好处是,我们可以实现简单的Dockerfile模版(比如在Dockerfile文件顶部增加包仓库或者更新包,从而尽可能保证缓存命中)。例如在Dockerfile文件顶部使用相同的指令集模版:
FROM ubuntu:14.04
MAINTAINER zhangqiang "[email protected]"
# 设置一个名为REFRESHED_AT的环境变量,表示镜像模板最后的更新时间
ENV REFRESHED_AT 2018-09-14
RUN apt-get -qq update
Docker Compose
实战
打包一个日志输出程序的镜像
准备
# 找个 java 镜像
$ docker search java
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
node Node.js is a JavaScript-based platform for s… 7176 [OK]
tomcat Apache Tomcat is an open source implementati… 2318 [OK]
java Java is a concurrent, class-based, and objec… 1960 [OK]
openjdk OpenJDK is an open-source implementation of … 1562 [OK]
...
# 提前拉到本地
$ docker pull java:8
# 看下内部情况
$ docker run -it java:8 /bin/bash
# 看下操作系统
root@f793c1e059ad:/# cat /etc/issue
Debian GNU/Linux 8 \n \l
# 看下系统内核
root@f793c1e059ad:/# cat /proc/version
Linux version 4.9.93-linuxkit-aufs (root@856d34d1168e) (gcc version 6.4.0 (Alpine 6.4.0) ) #1 SMP Wed Jun 6 16:55:56 UTC 2018
# 看下 java 版本
root@f793c1e059ad:/# java -version
openjdk version "1.8.0_111"
OpenJDK Runtime Environment (build 1.8.0_111-8u111-b14-2~bpo8+1-b14)
OpenJDK 64-Bit Server VM (build 25.111-b14, mixed mode)
# 好,假装看懂了,退出
root@f793c1e059ad:/# exit
构建镜像
# 构建上下文环境
$ mkdir log4j_jsonlogs
$ cd log4j_jsonlogs
# 把依赖 jar 放到上下文环境
$ mv /Users/zhangqiang/IdeaProjects/jsonlogs/out/artifacts/jsonlogs_jar/target/jsonlogs.jar .
# 编写 dockerfile
$ vim log4j2_logs.dockerfile
# 指定基础镜像
FROM java:8
# 作者信息
MAINTAINER zhangqiang "[email protected]"
# 在容器内部创建一个文件夹
RUN mkdir /home/log4j
# 将 contextDir 中的 jsonlogs.jar 拷贝到容器的 /home/log4j 目录下
# 注意: source 文件路径是相对于 contextDir 的,并且 docker 只能访问 contextDir 中的文件,如果访问 contextDir
# 之外的文件会出现 COPY failed: Forbidden path outside the build context: ../test (),如果想把
# contextDir 中的所有文件都拷贝到镜像内可以使用`COPY . /home/log4j`
COPY jsonlogs.jar /home/log4j
# 对外暴露端口
EXPOSE 80
# 当启动容器的时候执行的命令
CMD ["java", "-jar", "/home/log4j/jsonlogs.jar"]
# 构建镜像
$ docker build -t="myrepository/log4j2_logs:v1" -f ./log4j2_logs.dockerfile .
# 查看是否成功打进去了
$ docker run -it myrepository/log4j2_logs:v1 /bin/bash
root@2745f757d0bf:/home# ls -l /home/log4j/
-rw-r--r-- 1 root root 4335852 Mar 21 05:15 jsonlogs.jar
# 后台运行,并将宿主机的 4000 端口映射到容器暴露的 80 端口
$ docker run --name log4j2 -d -p 4000:80 --log-driver=json-file myrepository/log4j2_logs:v1
# 查看输出日志
$ docker logs log4j2
{"thread":"main","level":"ERROR","loggerName":"com.rich.LogGenerator","message":"java.lang.IllegalArgumentException: error log\n\tat com.rich.LogGenerator.nestedJsonLogs(LogGenerator.java:30)\n\tat com.rich.LogGenerator.main(LogGenerator.java:17)\n","endOfBatch":false,"loggerFqcn":"org.apache.logging.log4j.spi.AbstractLogger","instant":{"epochSecond":1553157695,"nanoOfSecond":647000000},"threadId":1,"threadPriority":5}
2019-03-21 08:41:35.035 com.rich.LogGenerator ERROR java.lang.IllegalArgumentException: error log
at com.rich.LogGenerator.nestedJsonLogs(LogGenerator.java:30)
at com.rich.LogGenerator.main(LogGenerator.java:17)
{"thread":"main","level":"INFO","loggerName":"com.rich.LogGenerator","message":{"girlfriend":"唐xx","province":"山东","name":"张x","age":"24"},"endOfBatch":false,"loggerFqcn":"org.apache.logging.log4j.spi.AbstractLogger","instant":{"epochSecond":1553157695,"nanoOfSecond":787000000},"threadId":1,"threadPriority":5}
...
将 docker image 上传到内网 docker 服务器
# 在公网机器
$ docker pull docker.elastic.co/beats/filebeat:6.4.0
# 查看本地镜像
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.elastic.co/beats/filebeat 6.4.0 9ef2f516cfe7 6 months ago 291MB
# 将本地镜像保存成 tar 文件
$ docker save -o filebeat.tar docker.elastic.co/beats/filebeat:6.4.0
# 将 tar 文件上传到内网服务器
# 加载到内网 docker
$ docker load -i filebeat.tar
# 查看本地 registry 地址,如果修改了 registry 地址记得重启服务才生效
$ vim /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=cgroupfs"],
"registry-mirrors": [],
"insecure-registries": ["192.168.51.35:5000"],
"debug": true,
"experimental": false
}
# 注意:insecure-registries 不需要执行登录操作,如果有认证的话要先登录
$ docker login $IMAGE_REGISTRY -u $RES_USER -p $RES_PASSWD
# 重新打标签
$ docker tag docker.elastic.co/beats/filebeat:6.4.0 192.168.51.35:5000/filebeat:6.4.0
# 查看本地镜像,可以看到相同 image id 不同库的两个镜像了
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.elastic.co/beats/filebeat 6.4.0 9ef2f516cfe7 6 months ago 291MB
192.168.51.35:5000/filebeat 6.4.0 9ef2f516cfe7 6 months ago 291MB
# 上传到本地 registry
$ docker push 192.168.51.35:5000/filebeat:6.4.0
The push refers to repository [192.168.51.35:5000/filebeat]
be5402f062d8: Pushed
175d99a09f10: Pushed
853290f56c1d: Pushed
4f90788cf2a5: Pushed
83bce82c7799: Pushed
9ea2263c9207: Pushed
1d31b5806ba4: Pushed
6.4.0: digest: sha256:739453f83c8c707c589d4e28c7a749581ea9d0511fd1ba2e3c97ae015800e103 size: 1786