欢迎关注:www.kumao.cool
Docker官网地址:https://www.docker.com
Docker文档
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。
一个完整的Docker有以下几个部分组成:
sudo apt-get remove docker docker-engine docker.io containerd runc
# 更新apt包索引,安装允许apt通过HTTPS访问仓库的包
sudo apt-get update
sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
# 添加Docker的官方GPG密钥
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# 设置镜像仓库
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
安装最新版的docker引擎,如果要安装指定版本,参考 https://docs.docker.com/engine/install/ubuntu/
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
moon@kumao:~$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
Reading package lists... Done
Building dependency tree
Reading state information... Done
Suggested packages:
aufs-tools cgroupfs-mount | cgroup-lite
The following NEW packages will be installed:
containerd.io docker-ce docker-ce-cli docker-compose-plugin
0 upgraded, 4 newly installed, 0 to remove and 214 not upgraded.
Need to get 0 B/99.2 MB of archives.
# ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
Processing triggers for ureadahead (0.100.0-21) ...
moon@kumao:~$
验证安装是否成功
sudo docker run hello-world
moon@kumao:~$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:faa03e786c97f07ef34423fccceeec2398ec8a5759259f94d99078f264e9d7af
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
# ...
For more examples and ideas, visit:
https://docs.docker.com/get-started/
moon@kumao:~$
Docker官方命令链接
systemctl status docker.service # 查看docker服务的运行状态
sudo systemctl stop docker.socket # 停止docker socket
sudo systemctl stop docker.service # 停止docker服务
sudo systemctl start docker.service. # 启动docker服务
sudo systemctl restart docker.service # 重启docker服务
moon@kumao:~$ systemctl status docker.service
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2022-12-07 09:49:14 CST; 3s ago
Docs: https://docs.docker.com
Main PID: 31131 (dockerd)
Tasks: 7
CGroup: /system.slice/docker.service
└─31131 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
docker --help # docker帮助命令
docker COMMAND --help # docker命令帮助命令
docker --version # 查看docker版本信息
docker info # 查看docker系统信息(客户端&服务端状态,镜像&容器的数量等)
docker images # 查看本地所有的镜像
docker search 镜像名 # 从仓库中搜索镜像
docker pull 镜像名[TAG] # 下载镜像(如果不写tag,默认是latest)
docker rmi 镜像名[TAG] # 删除镜像docker rmi -f $(docker images -aq)删除全部镜像
docker tag 镜像名:TAG 新镜像名:TAG # 复制出一个修改了名称的镜像
docker load -i /xxx/xxx.tar # 通过tar包导入镜像
docker save -o 镜像名 /xxx/xxx.tar # 保存一个镜像为一个tar包
root@kumao:/home/moon# docker pull redis:7.0.5
7.0.5: Pulling from library/redis
025c56f98b67: Pull complete
060e65aed679: Pull complete
b95291e865b7: Pull complete
7b879d654837: Pull complete
4538783c407f: Pull complete
ec5078f7c4e4: Pull complete
Digest: sha256:dfeb5451fce377ab47c5bb6b6826592eea534279354bbfc3890c0b5e9b57c763
Status: Downloaded newer image for redis:7.0.5
docker.io/library/redis:7.0.5
root@kumao:/home/moon# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
redis 7.0.5 3e12e2ceb68f 20 hours ago 117MB
hello-world latest feb5d9fea6a5 14 months ago 13.3kB
root@kumao:/home/moon#
moon@kumao:~/docker$ sudo docker save hello_world:1.0 -o ./hello_world_1.0.tar
moon@kumao:~/docker$ ls
hello_world_1.0.tar
moon@kumao:~/docker$ sudo docker load -i ./hello_world_1.0.tar
Loaded image: hello_world:1.0
docker history 镜像名称 # 查看docker镜像的变更历史
docker image inspect 镜像名称:标签 # 查看镜像元数据
root@kumao:/home/moon/docker/redis_data# docker history redis:7.0.5
IMAGE CREATED CREATED BY SIZE COMMENT
3e12e2ceb68f 23 hours ago /bin/sh -c #(nop) CMD ["redis-server"] 0B
<missing> 23 hours ago /bin/sh -c #(nop) EXPOSE 6379 0B
<missing> 23 hours ago /bin/sh -c #(nop) ENTRYPOINT ["docker-entry… 0B
<missing> 23 hours ago /bin/sh -c #(nop) COPY file:e873a0e3c13001b5… 661B
<missing> 23 hours ago /bin/sh -c #(nop) WORKDIR /data 0B
<missing> 23 hours ago /bin/sh -c #(nop) VOLUME [/data] 0B
<missing> 23 hours ago /bin/sh -c mkdir /data && chown redis:redis … 0B
<missing> 23 hours ago /bin/sh -c set -eux; savedAptMark="$(apt-m… 32MB
23 hours ago /bin/sh -c #(nop) ENV REDIS_DOWNLOAD_SHA=67… 0B
23 hours ago /bin/sh -c #(nop) ENV REDIS_DOWNLOAD_URL=ht… 0B
23 hours ago /bin/sh -c #(nop) ENV REDIS_VERSION=7.0.5 0B
23 hours ago /bin/sh -c set -eux; savedAptMark=" $(apt-ma… 4.13MB
<missing> 23 hours ago /bin/sh -c #(nop) ENV GOSU_VERSION=1.14 0B
<missing> 23 hours ago /bin/sh -c groupadd -r -g 999 redis && usera… 329kB
<missing> 28 hours ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 28 hours ago /bin/sh -c #(nop) ADD file:1f1efd56601ebc26a… 80.5MB
docker run [可选参数] image 命令 # 启动容器(无镜像会先下载镜像)
--name = "Name" 容器名字
-c 后面跟待完成的命令
-d 以后台方式运行并且返回ID,启动守护进程式容器
-i 使用交互方式运行容器,通常与t同时使用
-t 为容器重新分配一个伪输入终端。也即启动交互式容器
-p 指定容器端口 -p 容器端口:物理机端口 映射端口
-P 随机指定端口
-v 给容器挂载存储卷
root@kumao:/home/moon/docker# docker run -it --name="docker_redis" redis:7.0.5 /bin/bash
root@47dc1c3f847f:/data# ls
root@47dc1c3f847f:/data#
exit # 直接退出容器
crlt + p + q # 退出容器但是不终止运行
docker ps -a # 列出所有容器(不加-a就是在运行的)
docker stop 容器ID # 停止正在运行的容器
docker start 容器ID # 启动容器
docker restart 容器ID # 重启容器
docker kill 容器ID # 杀掉容器
root@kumao:/home/moon/docker# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fbe8daae9e9d redis:7.0.5 "docker-entrypoint.s…" 31 seconds ago Up 30 seconds 6379/tcp docker_redis02
root@kumao:/home/moon/docker# docker stop fbe8daae9e9d
fbe8daae9e9d
root@kumao:/home/moon/docker# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
root@kumao:/home/moon/docker# docker start fbe8daae9e9d
fbe8daae9e9d
root@kumao:/home/moon/docker# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fbe8daae9e9d redis:7.0.5 "docker-entrypoint.s…" About a minute ago Up 2 seconds 6379/tcp docker_redis02
root@kumao:/home/moon/docker# docker restart fbe8daae9e9d
fbe8daae9e9d
root@kumao:/home/moon/docker# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fbe8daae9e9d redis:7.0.5 "docker-entrypoint.s…" About a minute ago Up 3 seconds 6379/tcp docker_redis02
root@kumao:/home/moon/docker# docker kill fbe8daae9e9d
fbe8daae9e9d
root@kumao:/home/moon/docker# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
docker attach 容器ID
docker exec 容器ID
# 这两个同为 进入正在运行的容器 的命令,不同的是attach连接终止会让容器退出后台运行,而exec不会。
# docker attach是进入正在执行的终端,不会启动新的终端;而docker exec则会开启一个新的终端,可以在里面操作
root@kumao:/home/moon/docker# docker attach 47dc1c3f847f
root@47dc1c3f847f:/data# ls
root@47dc1c3f847f:/data# pwd
/data
root@47dc1c3f847f:/data# lsread escape sequence
root@kumao:/home/moon/docker# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
47dc1c3f847f redis:7.0.5 "docker-entrypoint.s…" About an hour ago Up 3 minutes 6379/tcp docker_redis
root@kumao:/home/moon/docker# docker exec -it 47dc1c3f847f /bin/bash
root@47dc1c3f847f:/data#
docker stats 容器ID # 查看容器状态(CPU和内存占用情况等)
docker logs 容器ID # 查看容器日志
docker top 容器ID # 查看容器内进程
docker rename 旧名字 新名字 # 给容器重新命名
docker rm 容器ID # 删除容器(正在运行容器不能删除,除非加-f选项)
root@kumao:/home/moon# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
47dc1c3f847f redis:7.0.5 "docker-entrypoint.s…" 2 hours ago Up 18 minutes 6379/tcp docker_redis01
root@kumao:/home/moon# docker top 47dc1c3f847f
UID PID PPID C STIME TTY TIME CMD
root 5664 5638 0 12:20 pts/0 00:00:00 /bin/bash
root 7111 5638 0 12:24 ? 00:00:00 /bin/bash
root@kumao:/home/moon#
docker cp 容器ID:容器内路径 目的主机路径 # 从容器内拷贝文件到主机(容器外同步到容器内使用挂载的方式)
root@kumao:/home/moon/docker# docker cp 47dc1c3f847f:/data/container_inner_file.txt ./
root@kumao:/home/moon/docker# ls
container_inner_file.txt hello_world_1.0.tar
创建容器时挂载数据卷
docker run -p 宿主机端口:容器端口 -it --name 容器名 -v 宿主机目录:容器目录 镜像 命令 # 具名挂载
docker run -p 宿主机端口:容器端口 -it --name 容器名 -v 容器目录 镜像 命令 # 匿名挂载
docker run -d -P --name nginx01 -v specific-nginx:/etc/nginx:ro nginx # 容器内只读
docker run -d -P --name nginx02 -v specific-nginx:/etc/nginx:rw nginx # 容器内可读可写
docker inspect 容器ID # 查看容器元信息
docker volume ls # 查看docker数据卷列表
docker inspect VOLUME_NAME # 查看数据卷信息
root@kumao:/home/moon/docker/redis_data# docker run -p 9999:6379 -it --name "redis_container03" -v /home/moon/docker/redis_data:/data redis:5.0.7 /bin/bash
Unable to find image 'redis:5.0.7' locally
5.0.7: Pulling from library/redis
68ced04f60ab: Pull complete
7ecc253967df: Pull complete
765957bf98d4: Pull complete
52f16772e1ca: Pull complete
2e43ba99c3f3: Pull complete
d95576c71392: Pull complete
Digest: sha256:938ee5bfba605cc85f9f52ff95024e9a24cf5511ba6f1cbc68ec9d91a0432125
Status: Downloaded newer image for redis:5.0.7
root@d52624399bbb:/data# ls
container_outer_file.txt
root@d52624399bbb:/data#
root@kumao:/home/moon/docker/redis_data# docker inspect d52624399bbb
[
{
"Id": "d52624399bbbc15d0a0a965b9867576cd70d73ebc6102b5d6a48c51efb94dc1e",
......
"Mounts": [ # 容器挂载信息
{
"Type": "bind",
"Source": "/home/moon/docker/redis_data",
"Destination": "/data",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
......
}
]
通过容器创建新的镜像
docker commit [OPTIONS] 容器ID [REPOSITORY[:TAG]] # 通过修改过的容器创建一个新的镜像
-a 提交的镜像作者
-c 应用Dockerfile指令来创建镜像
-m 提交时的说明文字
-p 提交时暂停容器运行
root@kumao:/home/moon/docker/redis_data# docker commit -a 'moon' -m '测试通过容器创建一个新的redis镜像' -p 47dc1c3f847f my_redis:1.0
sha256:efe0f631bd658add27c30dd34442894d4559b118c31e4ffb7c01fe9a8e7dbfd4
root@kumao:/home/moon/docker/redis_data# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
my_redis 1.0 efe0f631bd65 4 seconds ago 117MB
redis 7.0.5 3e12e2ceb68f 23 hours ago 117MB
hello_world 1.0 feb5d9fea6a5 14 months ago 13.3kB
hello-world latest feb5d9fea6a5 14 months ago 13.3kB
redis 5.0.7 7eed8df88d3b 2 years ago 98.2MB
设置要制作的镜像基于哪个镜像,FROM指令必须是整个Dockerfile的第一个指令,如果指定的镜像不存在默认会自动从Docker Hub上下载
镜像作者的信息,比如名字或邮箱地址
构建镜像时运行的shell命令
CMD指令中指定的命令会在镜像运行时执行,在Dockerfile中只能存在一个,如果使用了多个CMD指令,则只有最后一个CMD指令有效。当出现ENTRYPOINT指令时,CMD中定义的内容会作为ENTRYPOINT指令的默认参数,也就是说可以使用CMD指令给ENTRYPOINT传递参数
声明容器的服务端口
拷贝文件或目录到镜像容器内,如果是URL或压缩包会自动下载或自动解压
拷贝文件或目录到镜像容器内,跟ADD类似,但不具备自动下载或解压功能
设置容器的环境变量
(1)ENTRYPOINT指令中指定的命令会在镜像运行时执行,在Dockerfile中只能存在一个,如果使用了多个ENTRYPOINT指令,则只有最后一个指令有效。
(2)ENTRYPOINT指令中指定的命令(exec执行的方式)可以通过docker run来传递参数,例如docker run images -l启动的容器将会把-l参数传递给ENTRYPOINT指令定义的命令并会覆盖CMD指令中定义的默认参数(如果有的话),但不会覆盖该指令定义的参数,例如ENTRYPOINT [“ls”,“-a”],CMD [“/etc”],当通过docker run image启动容器时该容器会运行ls -a /etc命令,当使用docker run image -l启动时该容器会运行ls -a -l命令,-l参数会覆盖CMD指令中定义的/etc参数
VOLUME指令用来设置一个挂载点,可以用来让其他容器挂载以实现数据共享或对容器数据的备份、恢复或迁移
USER指令用于设置用户或uid来运行生成的镜像和执行RUN,CMD和ENTYRYPOINT执行命令
WORKDIR指令用于设置Dockerfile中的RUN、CMD和ENTRYPOINT指令执行命令的工作目录(默认为/目录),该指令在Dockerfile文件中可以出现多次,如果使用相对路径则为相对于WORKDIR上一次的值,例如WORKDIR /data,WORKDIR logs,RUN pwd最终输出的当前目录是/data/logs
ONBUILD指令用来设置一些触发的指令,用于在当该镜像被作为基础镜像来创建其他镜像时(也就是Dockerfile中的FROM为当前镜像时)执行一些操作,ONBUILD中定义的指令会在用于生成其他镜像的Dockerfile文件的FROM指令之后被执行,上述介绍的任何一个指令都可以用于ONBUILD指令,可以用来执行一些因为环境而变化的操作,使镜像更加通用
redis官方镜像的Dockerfile
FROM debian:bullseye-slim # 基于debian:bullseye-slim镜像
RUN groupadd -r -g 999 redis && useradd -r -g redis -u 999 redis # 执行shell命令添加用户
ENV GOSU_VERSION 1.14 # 设置环境变量GOSU_VERSION
# 执行了一大段shell脚本
RUN set -eux; \
savedAptMark="$(apt-mark showmanual)"; \
apt-get update; \
apt-get install -y --no-install-recommends ca-certificates dirmngr gnupg wget; \
rm -rf /var/lib/apt/lists/*; \
dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \
wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \
wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \
export GNUPGHOME="$(mktemp -d)"; \
gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \
gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \
gpgconf --kill all; \
rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \
apt-mark auto '.*' > /dev/null; \
[ -z "$savedAptMark" ] || apt-mark manual $savedAptMark > /dev/null; \
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
chmod +x /usr/local/bin/gosu; \
gosu --version; \
gosu nobody true
ENV REDIS_VERSION 7.0.5 # 设置环境变量
ENV REDIS_DOWNLOAD_URL http://download.redis.io/releases/redis-7.0.5.tar.gz
ENV REDIS_DOWNLOAD_SHA 67054cc37b58c125df93bd78000261ec0ef4436a26b40f38262c780e56315cc3
RUN set -eux; \
\
savedAptMark="$(apt-mark showmanual)"; \
apt-get update; \
apt-get install -y --no-install-recommends \
ca-certificates \
wget \
\
dpkg-dev \
gcc \
libc6-dev \
libssl-dev \
make \
; \
rm -rf /var/lib/apt/lists/*; \
\
wget -O redis.tar.gz "$REDIS_DOWNLOAD_URL"; \
echo "$REDIS_DOWNLOAD_SHA *redis.tar.gz" | sha256sum -c -; \
mkdir -p /usr/src/redis; \
tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1; \
rm redis.tar.gz; \
\
# disable Redis protected mode [1] as it is unnecessary in context of Docker
# (ports are not automatically exposed when running inside Docker, but rather explicitly by specifying -p / -P)
# [1]: https://github.com/redis/redis/commit/edd4d555df57dc84265fdfb4ef59a4678832f6da
grep -E '^ *createBoolConfig[(]"protected-mode",.*, *1 *,.*[)],$' /usr/src/redis/src/config.c; \
sed -ri 's!^( *createBoolConfig[(]"protected-mode",.*, *)1( *,.*[)],)$!\10\2!' /usr/src/redis/src/config.c; \
grep -E '^ *createBoolConfig[(]"protected-mode",.*, *0 *,.*[)],$' /usr/src/redis/src/config.c; \
# for future reference, we modify this directly in the source instead of just supplying a default configuration flag because apparently "if you specify any argument to redis-server, [it assumes] you are going to specify everything"
# see also https://github.com/docker-library/redis/issues/4#issuecomment-50780840
# (more exactly, this makes sure the default behavior of "save on SIGTERM" stays functional by default)
\
# https://github.com/jemalloc/jemalloc/issues/467 -- we need to patch the "./configure" for the bundled jemalloc to match how Debian compiles, for compatibility
# (also, we do cross-builds, so we need to embed the appropriate "--build=xxx" values to that "./configure" invocation)
gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; \
extraJemallocConfigureFlags="--build=$gnuArch"; \
# https://salsa.debian.org/debian/jemalloc/-/blob/c0a88c37a551be7d12e4863435365c9a6a51525f/debian/rules#L8-23
dpkgArch="$(dpkg --print-architecture)"; \
case "${dpkgArch##*-}" in \
amd64 | i386 | x32) extraJemallocConfigureFlags="$extraJemallocConfigureFlags --with-lg-page=12" ;; \
*) extraJemallocConfigureFlags="$extraJemallocConfigureFlags --with-lg-page=16" ;; \
esac; \
extraJemallocConfigureFlags="$extraJemallocConfigureFlags --with-lg-hugepage=21"; \
grep -F 'cd jemalloc && ./configure ' /usr/src/redis/deps/Makefile; \
sed -ri 's!cd jemalloc && ./configure !&'"$extraJemallocConfigureFlags"' !' /usr/src/redis/deps/Makefile; \
grep -F "cd jemalloc && ./configure $extraJemallocConfigureFlags " /usr/src/redis/deps/Makefile; \
\
export BUILD_TLS=yes; \
make -C /usr/src/redis -j "$(nproc)" all; \
make -C /usr/src/redis install; \
\
# TODO https://github.com/redis/redis/pull/3494 (deduplicate "redis-server" copies)
serverMd5="$(md5sum /usr/local/bin/redis-server | cut -d' ' -f1)"; export serverMd5; \
find /usr/local/bin/redis* -maxdepth 0 \
-type f -not -name redis-server \
-exec sh -eux -c ' \
md5="$(md5sum "$1" | cut -d" " -f1)"; \
test "$md5" = "$serverMd5"; \
' -- '{}' ';' \
-exec ln -svfT 'redis-server' '{}' ';' \
; \
\
rm -r /usr/src/redis; \
\
apt-mark auto '.*' > /dev/null; \
[ -z "$savedAptMark" ] || apt-mark manual $savedAptMark > /dev/null; \
find /usr/local -type f -executable -exec ldd '{}' ';' \
| awk '/=>/ { print $(NF-1) }' \
| sort -u \
| xargs -r dpkg-query --search \
| cut -d: -f1 \
| sort -u \
| xargs -r apt-mark manual \
; \
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
\
redis-cli --version; \
redis-server --version
RUN mkdir /data && chown redis:redis /data # 执行shell命令
VOLUME /data # 设置一个挂载点(其实就是一个目录)
WORKDIR /data # 运行容器后进入/data目录
COPY docker-entrypoint.sh /usr/local/bin/ # 把一个shell脚本拷贝到镜像内
ENTRYPOINT ["docker-entrypoint.sh"] # 运行容器时执行
EXPOSE 6379 # 运行容器时暴露的端口
CMD ["redis-server"] # 运行容器时执行的命令
准备工作
moon@kumao:~/docker$ ls -l
total 156036
-rw-r--r-- 1 moon moon 11613418 Dec 7 17:08 apache-tomcat-9.0.70.tar.gz
-rw-r--r-- 1 moon moon 148162542 Dec 7 17:19 jdk-8u341-linux-x64.tar.gz
-rw-rw-r-- 1 moon moon 0 Dec 7 17:25 readme.txt
moon@kumao:~/docker$
动手
# 基于ubuntu镜像
FROM ubuntu
# 作者
MAINTAINER wangguoqiang
# 拷贝readme文件到某个目录
COPY ./readme.txt /usr/local/readme.txt
# 添加jdk(构建时会自动解压)
ADD ./jdk-8u341-linux-x64.tar.gz /usr/local/
# 添加tomcat安装包
ADD ./apache-tomcat-9.0.70.tar.gz /usr/local/
USER root
# 安装vim
RUN apt-get update && apt-get install -y vim
# 设置环境变量MYPATH
ENV MYPATH /usr/local
# 工作目录
WORKDIR $MYPATH
# 配置一些tomcat需要的环境
ENV JAVA_HOME /usr/local/jdk1.8.0_341
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.70
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.70
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:CATALINA_HOME/bin
# 暴露端口
EXPOSE 8080
# 启动容器时执行的命令
CMD /usr/local/apache-tomcat-9.0.70/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.70/bin/logs/catalina.out
构建出自己的tomcat镜像
docker build [OPTIONS] PATH | URL | -
docker build -f dockerfiles/Dockerfile.debug -t myapp_debug . # 构建镜像(注意最后的.)
moon@kumao:~/docker$ ls
apache-tomcat-9.0.70.tar.gz Dockerfile jdk-8u341-linux-x64.tar.gz readme.txt
moon@kumao:~/docker$ sudo docker build -t mytomcat:0.1 .
Sending build context to Docker daemon 159.8MB
Step 1/16 : FROM ubuntu
---> a8780b506fa4
# ......
Removing intermediate container b37e47033b89
---> 9bfe74230266
Successfully built 9bfe74230266
Successfully tagged mytomcat:0.1
# 成功构建出mytomcat:0.1镜像
moon@kumao:~/docker$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat 0.1 9bfe74230266 About a minute ago 563MB
my_redis 1.0 efe0f631bd65 5 hours ago 117MB
redis 7.0.5 3e12e2ceb68f 28 hours ago 117MB
debian bullseye-slim 9f94f3391d54 33 hours ago 80.5MB
ubuntu latest a8780b506fa4 4 weeks ago 77.8MB
hello-world latest feb5d9fea6a5 14 months ago 13.3kB
hello_world 1.0 feb5d9fea6a5 14 months ago 13.3kB
redis 5.0.7 7eed8df88d3b 2 years ago 98.2MB
# 通过自己构建的镜像启动tomcat容器,并测试可用
moon@kumao:~/docker$ sudo docker run -d -p 8888:8080 --name moontomcat mytomcat:0.1
aafba278a66f06782e19283a5e4913850159e1e30dcc1206214302d651291816
moon@kumao:~/docker$ curl 0.0.0.0:8888
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Apache Tomcat/9.0.70</title>
<link href="favicon.ico" rel="icon" type="image/x-icon" />
<link href="tomcat.css" rel="stylesheet" type="text/css" />
</head>
......
</html>
参考这篇博客
Docker默认提供了3种网络模式,生成容器时不指定网络模式下默认使用bridge桥接模式
docker network ls # 使用命令查看当前Docker所有的网络模式
root@kumao:/home/moon# docker network ls
NETWORK ID NAME DRIVER SCOPE
3484ceee917e bridge bridge local
3b423e9b640f host host local
8b3561ed22a6 none null local
如果启动容器时使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口宿主机就不能再用了,网络的隔离性不好。
Namespace的简要说明:
Docker使用了Linux的Namespaces技术来进行资源隔离,如PID Namespace隔离进程,Mount Namespace隔离文件系统,Network Namespace隔离网络等。一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、Iptable规则等都与其他的NetworkNamespace隔离。一个Docker容器一般会分配一个独立的Network Namespace
这个模式指定新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。
使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。这种网络模式下容器只有lo回环网络,没有其他网卡。none模式可以在容器创建时通过–network=none来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。
bridge模式是docker的默认网络模式,不写–net参数,就是bridge模式。使用docker run -p时,docker实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL查看。
当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器都会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。
从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过brctl show命令查看。
从上图中我们可以看到,可以看到容器内部和Linux主机都会创建一个新的网卡,而这两个网卡都是成对的。使用的技术就是evth-pair。evth-pair 就是一对的虚拟设备接口,他们是成对出现的,一段连着协议,一段彼此相连。evth-pair充当一个桥梁,连接各种虚拟网络设备。
Docker容器完成bridge网络配置的过程如下:
宿主机和Docker容器之间是可以进行网络连接的,同样的,Docker容器和容器之间也可以直接进行网络连接。
容器1和容器2,都使用公用的路由器docker0。所有的容器在不指定网络情况下,都是由docker0路由的,Docker会给我们容器默认分配一个随机的可用IP地址,这些IP地址之间是可以进行网络交互的。
在微服务部署的场景下,注册中心是使用服务名来唯一识别微服务的,而我们上线部署的时候微服务对应的IP地址可能会改动,所以我们需要使用容器名来配置容器间的网络连接,使–link选项可以完成这个功能。
首先不设置–link的情况下,是无法通过容器名来进行连接的。ubuntu02容器是可以直接ping通ubuntu01,但是无法ping通ubuntu01的容器名。
root@kumao:/home/moon# docker network ls
NETWORK ID NAME DRIVER SCOPE
3484ceee917e bridge bridge local
3b423e9b640f host host local
8b3561ed22a6 none null local
root@kumao:/home/moon# docker network inspect 3484ceee917
# ...
"31cfcf19618076a82680553a888bd2bc8e9de80f63d0d86f229baea07112900a": {
"Name": "ubuntu01",
"EndpointID": "50d22b03e487c4778ffdea0d93bf01c8b187d666aed8ebccab7dd7f494a80aa0",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
},
"c1a5e763fe528b336fa02ffd9c722dbb8f689fd217435ebc042d2a3bf43b0f63": {
"Name": "ubuntu02",
"EndpointID": "cc2fa5386dd8fa9e140b6fc166445e9393404a1d706c5b9eb7a74a454249d47c",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": ""
}
# ...
root@kumao:/home/moon# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c1a5e763fe52 ubuntu "/bin/bash" 2 hours ago Up 2 hours ubuntu02
31cfcf196180 ubuntu "/bin/bash" 3 hours ago Up 3 hours ubuntu01
root@kumao:/home/moon# docker exec ubuntu02 ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: icmp_seq=0 ttl=64 time=0.182 ms
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.184 ms
^C
root@kumao:/home/moon# docker exec ubuntu02 ping ubuntu01
ping: unknown host
root@kumao:/home/moon#
添加参数–link,可以通过容器名进行连接。ubuntu03容器link到ubuntu01,所以ubuntu03可以直接通过容器名ping通ubuntu01,但是反过来ubuntu01去ping ubuntu03容器名是ping不通的。
root@kumao:/home/moon# docker run -it --name ubuntu03 --link ubuntu01 myubuntu
root@kumao:/home/moon# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
458748d7f67f myubuntu "/bin/bash" 9 seconds ago Up 8 seconds ubuntu03
c1a5e763fe52 ubuntu "/bin/bash" 3 hours ago Up 3 hours ubuntu02
31cfcf196180 ubuntu "/bin/bash" 3 hours ago Up 3 hours ubuntu01
root@kumao:/home/moon# docker exec ubuntu03 ping ubuntu01
PING ubuntu01 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: icmp_seq=0 ttl=64 time=0.219 ms
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.123 ms
64 bytes from 172.18.0.2: icmp_seq=2 ttl=64 time=0.148 ms
^C
root@kumao:/home/moon# docker exec ubuntu01 ping ubuntu03
ping: unknown host
root@kumao:/home/moon#
–-link的原理就是在ubuntu03容器的hosts文件中添加了要去link的ubuntu01容器的容器名和ip地址映射。但是因为docker0不支持容器名访问,所以–-link设置容器互连的方式不推荐使用,更多地选择自定义网络。
docker network --help # docker网络帮助命令
root@kumao:/home/moon# 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
Run 'docker network COMMAND --help' for more information on a command.
root@kumao:/home/moon#
root@kumao:/home/moon# docker network create --help
Usage: docker network create [OPTIONS] NETWORK
Create a network
Options:
--attachable Enable manual container attachment
--aux-address map Auxiliary IPv4 or IPv6 addresses used by Network driver (default map[])
--config-from string The network from which to copy the configuration
--config-only Create a configuration only network
-d, --driver string Driver to manage the Network (default "bridge")
--gateway strings IPv4 or IPv6 Gateway for the master subnet
--ingress Create swarm routing-mesh network
--internal Restrict external access to the network
--ip-range strings Allocate container ip from a sub-range
--ipam-driver string IP Address Management Driver (default "default")
--ipam-opt map Set IPAM driver specific options (default map[])
--ipv6 Enable IPv6 networking
--label list Set metadata on a network
-o, --opt map Set driver specific options (default map[])
--scope string Control the network's scope
--subnet strings Subnet in CIDR format that represents a network segment
root@kumao:/home/moon#
自定义的docker网络mynet,网关192.158.0.1,子网192.158.0.0/16,后续创建容器时可用之。使用自定义网络创建容器后,使用相同网络下的容器,不管是通过容器IP还是容器名,都可以进行网络通信。
root@kumao:/home/moon# docker network create -d bridge --gateway 192.158.0.1 --subnet 192.158.0.0/16 mynet
1149ddd3e8874e55999a491a36983c2b807f9d9746dbd152102635b6fca5515a
root@kumao:/home/moon# docker network ls
NETWORK ID NAME DRIVER SCOPE
3484ceee917e bridge bridge local
3b423e9b640f host host local
1149ddd3e887 mynet bridge local
8b3561ed22a6 none null local
root@kumao:/home/moon#
root@kumao:/home/moon# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "1149ddd3e8874e55999a491a36983c2b807f9d9746dbd152102635b6fca5515a",
"Created": "2022-12-08T13:39:11.79885784+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.158.0.0/16",
"Gateway": "192.158.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"631f8ba964f47482cec295e4942e906bc4532a4a00e6dbf16ae399640e1403d8": {
"Name": "ubuntu-net-02",
"EndpointID": "4754e604d3010aa921424f04622e99cb7244eb69c045d2bf4deb8e8e8bf56839",
"MacAddress": "02:42:c0:9e:00:03",
"IPv4Address": "192.158.0.3/16",
"IPv6Address": ""
},
"d0c6f9ebd6be415b5613835024025638ea0a7116b3fff12f5f38d57c4f77092e": {
"Name": "ubuntu-net-01",
"EndpointID": "98b6cd68bb14d85bac02e4cdb4df83f88ab760e0c6695274d996f85f919726f6",
"MacAddress": "02:42:c0:9e:00:02",
"IPv4Address": "192.158.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
root@kumao:/home/moon#
root@kumao:/home/moon# docker run -it --name ubuntu-net-01 --net mynet myubuntu /bin/bash
root@kumao:/home/moon# docker run -it --name ubuntu-net-02 --net mynet myubuntu /bin/bash
root@kumao:/home/moon# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
631f8ba964f4 myubuntu "/bin/bash" 57 seconds ago Up 55 seconds ubuntu-net-02
d0c6f9ebd6be myubuntu "/bin/bash" About a minute ago Up About a minute ubuntu-net-01
458748d7f67f myubuntu "/bin/bash" 32 minutes ago Up 32 minutes ubuntu03
c1a5e763fe52 ubuntu "/bin/bash" 3 hours ago Up 3 hours ubuntu02
31cfcf196180 ubuntu "/bin/bash" 3 hours ago Up 3 hours ubuntu01
root@kumao:/home/moon# docker exec ubuntu-net-01 ping ubuntu-net-02
PING ubuntu-net-02 (192.158.0.3): 56 data bytes
64 bytes from 192.158.0.3: icmp_seq=0 ttl=64 time=0.115 ms
64 bytes from 192.158.0.3: icmp_seq=1 ttl=64 time=0.097 ms
64 bytes from 192.158.0.3: icmp_seq=2 ttl=64 time=0.100 ms
^C
root@kumao:/home/moon# docker exec ubuntu-net-02 ping ubuntu-net-01
PING ubuntu-net-01 (192.158.0.2): 56 data bytes
64 bytes from 192.158.0.2: icmp_seq=0 ttl=64 time=0.121 ms
64 bytes from 192.158.0.2: icmp_seq=1 ttl=64 time=0.133 ms
64 bytes from 192.158.0.2: icmp_seq=2 ttl=64 time=0.152 ms
^C
root@kumao:/home/moon# docker exec ubuntu-net-01 ping 192.158.0.3
PING 192.158.0.3 (192.158.0.3): 56 data bytes
64 bytes from 192.158.0.3: icmp_seq=0 ttl=64 time=0.174 ms
64 bytes from 192.158.0.3: icmp_seq=1 ttl=64 time=0.157 ms
^C
在没有使用connect命令的情况下,不同网络间的容器是无法进行网络连接的
root@kumao:/home/moon# docker exec ubuntu01 ping ubuntu-net-02
ping: unknown host
root@kumao:/home/moon#
不同Docker网络之间的容器想要连接的话,需要把该容器注册到另一个容器所在的网络上,使用docker connect命令
root@kumao:/home/moon# 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
root@kumao:/home/moon# docker network connect mynet ubuntu01
root@kumao:/home/moon#
root@kumao:/home/moon# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "1149ddd3e8874e55999a491a36983c2b807f9d9746dbd152102635b6fca5515a",
"Created": "2022-12-08T13:39:11.79885784+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.158.0.0/16",
"Gateway": "192.158.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"31cfcf19618076a82680553a888bd2bc8e9de80f63d0d86f229baea07112900a": {
"Name": "ubuntu01", # 其实就是把ubuntu01加入到mynet网络,这时ubuntu01有两个IP
"EndpointID": "abad6fbcb038cf631974e2e3cd20c23effb26ee7072f226fb514aa697ce30f60",
"MacAddress": "02:42:c0:9e:00:04",
"IPv4Address": "192.158.0.4/16",
"IPv6Address": ""
},
"631f8ba964f47482cec295e4942e906bc4532a4a00e6dbf16ae399640e1403d8": {
"Name": "ubuntu-net-02",
"EndpointID": "4754e604d3010aa921424f04622e99cb7244eb69c045d2bf4deb8e8e8bf56839",
"MacAddress": "02:42:c0:9e:00:03",
"IPv4Address": "192.158.0.3/16",
"IPv6Address": ""
},
"d0c6f9ebd6be415b5613835024025638ea0a7116b3fff12f5f38d57c4f77092e": {
"Name": "ubuntu-net-01",
"EndpointID": "98b6cd68bb14d85bac02e4cdb4df83f88ab760e0c6695274d996f85f919726f6",
"MacAddress": "02:42:c0:9e:00:02",
"IPv4Address": "192.158.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
root@kumao:/home/moon#
root@kumao:/home/moon# docker exec ubuntu01 ping ubuntu-net-01
PING ubuntu-net-01 (192.158.0.2): 56 data bytes
64 bytes from 192.158.0.2: icmp_seq=0 ttl=64 time=0.230 ms
64 bytes from 192.158.0.2: icmp_seq=1 ttl=64 time=0.158 ms
^C
root@kumao:/home/moon# docker exec ubuntu01 ping ubuntu-net-02
PING ubuntu-net-02 (192.158.0.3): 56 data bytes
64 bytes from 192.158.0.3: icmp_seq=0 ttl=64 time=0.197 ms
64 bytes from 192.158.0.3: icmp_seq=1 ttl=64 time=0.201 ms
^C
root@kumao:/home/moon# docker exec ubuntu-net-01 ping ubuntu01
PING ubuntu01 (192.158.0.4): 56 data bytes
64 bytes from 192.158.0.4: icmp_seq=0 ttl=64 time=0.214 ms
64 bytes from 192.158.0.4: icmp_seq=1 ttl=64 time=0.219 ms
64 bytes from 192.158.0.4: icmp_seq=2 ttl=64 time=0.217 ms
^C