前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Docker 入门笔记

Docker 入门笔记

作者头像
Rikka
发布2022-01-20 10:22:17
1.1K0
发布2022-01-20 10:22:17
举报
文章被收录于专栏:rikkarikka

Docker 概述

容器化, 每个容器隔离. 不是模拟一个完整的操作系统. 容器没有自己的内核

Docker 将环境打包在一起

  • 应用更快速的交付和部署
    • 打包镜像, 一键运行
  • 更便捷的升级和扩缩容
    • 打包镜像, 轻易扩展
  • 更简单的系统运维
    • 开发测试环境一致 明明在我的电脑上能运行的!
  • 更高效的计算资源利用
    • 内核级别虚拟化, 压榨性能

Docker 的基本组成

  • 镜像 (image)
    • 如同模版, 镜像—run—>容器, 一个镜像可以创建多个容器
  • 容器(container)
    • 独立运行一个或者一个组应用
    • 基本命令启动, 停止, 删除
  • 仓库(Registry)
    • 存放镜像的地方(Dockerhub)
  • 客户端 (Client)
    • 向服务器发送请求, 支持很多命令
  • 服务器 (Server)
    • Docker daemon: 服务器组件, linux 后台服务, 负责创建、运行、监控容器, 构建、存储镜像

Docker 的原理

Client

Client

Client

Client

Docker Daemon

Docker Daemon

Container

Container

Container

ContainerViewer does not support full SVG 1.1

Docker 为什么比虚拟机更快: 更少的抽象层

Docker 常用命令

帮助命令

代码语言:javascript
复制
docker version		
docker info			# docker 系统信息 
docker 命令 --help

镜像命令

docker images

代码语言:javascript
复制
❯ docker images
REPOSITORY                TAG             IMAGE ID       CREATED        SIZE
hagb/docker-easyconnect   cli             f3c06cd4a55c   4 weeks ago    117MB
hagb/docker-easyconnect   vncless-7.6.3   e9d950d9c373   4 weeks ago    373MB
hello-world               latest          d1165f221234   5 months ago   13.3kB
代码语言:javascript
复制
# 可选项
    -a, --all # 显示所有的镜像
    -q, --quiet # 只显示 id

docker search 搜索镜像

代码语言:javascript
复制
--filter # 过滤

docker pull 下载镜像

代码语言:javascript
复制
# docker pull 镜像名[:tag] 默认下载最新版
❯ docker pull mysql:5.7
5.7: Pulling from library/mysql
e1acddbe380c: Pull complete 		# 分层次下载, 如果已经存在则不需要重新下载, 节省内存
bed879327370: Pull complete 
03285f80bafd: Pull complete 
ccc17412a00a: Pull complete 
1f556ecc09d1: Pull complete 
adc5528e468d: Pull complete 
1afc286d5d53: Pull complete 
4d2d9261e3ad: Pull complete 
ac609d7b31f8: Pull complete 
53ee1339bc3a: Pull complete 
b0c0a831a707: Pull complete 
Digest: sha256:7cf2e7d7ff876f93c8601406a5aa17484e6623875e64e7acc71432ad8e0a3d7e
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7			# 真实地址

docker rmi 删除

代码语言:javascript
复制
docker rmi -f $(docker images -aq) 	# 删除所有镜像

docker commit 提交容器

代码语言:javascript
复制
docker commit -m="message" -a="author" CONTAINER NAME[:TAG] # 将容器保存为新的副本

容器命令

以 centos 为例

代码语言:javascript
复制
docker pull centos

新建容器并启动

代码语言:javascript
复制
docker run [可选] image

# 参数说明
--name="Name"	# 容器名字
-d				# 后台方式运行. 如果没有前台进程, docker 会自动停止后台应用
-it				# 使用交互方式运行, 进入容器查看内容
-p				# 指定容器的端口 
	-p ip 主机端口:容器端口
	-p 主机端口:容器端口(常用)
	-p 容器端口
	容器端口
-P				# 随机指定端口

举例:

列出所有运行的容器

代码语言:javascript
复制
docker ps [OPTIONS]
Options: 
	-a: 列出所有容器(默认是正在运行的)
	-n=?: 显示最近创建的容器
	-q: 只显示容器的编号

退出容器

代码语言:javascript
复制
exit # 停止运行并退出容器
Ctrl+P+Q # 不停止退出容器

删除容器

代码语言:javascript
复制
docker rm 容器id
docker rm -f $(docker ps -aq)
docker ps -aq | xargs docker rm

启动和停止容器

代码语言:javascript
复制
docker start id
docker restart id
docker stop id
docker kill id

其他

代码语言:javascript
复制
docker exec -it ID /bin/bash 	# 进入正在运行的容器, 开启新的终端
docker attach ID				# 进入正在执行的终端, 不开启新的
docker logs	ID	 			 	# 查看日志
docker top ID 				 	# 查看容器内进程 
docker inspect ID   			# 查看容器元数据
docker cp ID:SRC_PATH DEST_PATH # 拷贝文件

练习

部署 nginx

代码语言:javascript
复制
docker pull nginx 
docker run -d --name nginx01 -p 3344:80 nginx	# 后台运行, 80端口映射到宿主机 3344 端口
docker exec -it nginx01 /bin/bash 				# 进入容器内部

每次改配置文件, 都要进如容器很麻烦——使用数据卷

部署 tomcat

代码语言:javascript
复制
docker run -it --name   tomcat01 -p 3355:8080  tomcat 

部署 elasticsearch + kibana

代码语言:javascript
复制
docker run -it --name   tomcat01 -p 3355:8080  tomcat 

从宿主机的 3355 端口访问可以看到

部署 elasticsearch + kibana

代码语言:javascript
复制
docker run -d --name es -p 9200:9200 -p 9300:9300  -e "discovery.types=single-node" -e ES_JAVA_OPS="-Xms64m -Xmx512m" elasticsearch
Unable to find image 'elasticsearch:latest' locally # 限制最小最大内存
docker stats # 查看 CPU 和内存占用

两个服务部署在两个容器, 如何对接?

可视化

portainer (无用)

代码语言:javascript
复制
docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
  • Rancher

Docker 镜像

镜像是什么

镜像是一种轻量级的、可以独立执行的独立软件包, 用来打包软件运行环境和运行环境开发的软件, 它包含某个软件运行需要的全部内容, 包括环境变量、代码、运行时库和配置文件

Docker 的组成

Docker 镜像加载原理

典型的 Linux 文件系统由 bootfs (boot file system) 和 rootfs(root file system) 组成.

bootfs: 包含 bootloader 和 kernel. bootloader 负责引导加载 kernel. 内核加载进内存后 bootfs 被卸载

rootfs: Linux 系统中的 /dev, /proc, /etc 等标准目录和文件

Docker 镜像建立在 AUFS (一种 UnionFS) 之上, UnionFS 支持对文件系统的修改作为一次提交来一层层叠加, 同时可以将不同目录挂载到同一个虚拟文件系统下.UnionFS 一次加载多层只读 (read only)的 rootfs, 但从外面看来只能看到一个 rootfs. 联合加载 (union mount) 的这些叠加起来的 roofts 就是 Docker 镜像. 镜像实例化后会分配一层空的 read-write 的 roofts==>容器层.

以下部分内容节选并翻译自 https://docs.docker.com/storage/volumes/

(volumes)是持久化由 Docker 容器产生和使用的数据的首选机制. 绑定挂载 (bind mounts) 依赖于目录结构以及宿主机的操作系统, 而卷完全由 Docker 管理. 相比绑定挂载, 卷有以下几个优点:

  • 卷更加容易备份和迁移
  • 可以使用 Docker CLI 命令或者 Docker API 来管理卷
  • 卷在 Linux 和 Windows 系统均可工作
  • 卷驱动允许将卷存储在远程主机或是云提供商, 以加密卷的内容或是添加其他功能
  • 新的卷可以由容器预填充内容
  • Docker Desktop 上的卷比 Mac 和 Windows 宿主机上的绑定挂载具有更高的性能

绑定挂载 (bind mounts) 在命令上与卷 (volumes)很相似, -v 三个字段为: 宿主机目录, 容器内挂载目录和读写权限(可选).

如果容器生成非持久状态数据, 请考虑使用 tmpfs mount, 以避免永久地将数据存储在什么地方, 并通过避免对容器的可写层 (writable layer) 写入来提升容器性能.

选择 -v 或者 —mount 标志

一般来讲, --mount 更明确详细, 最大的区别是 -v 将所有的选项合并在一个字段, --mount 则是分开的. 下面是两种语法的比较.

如果你想具体指定卷驱动的选项, 必须使用 --mount.

  • -v 或者 --volume: 由三个字段组成, 由冒号 ( : ) 分隔.字段中的顺序必须正确, 并且每个字段的含义并不是显而易见的.
    • 具名卷 (named volumes) 的情况下, 第一个字段是卷名, 这在宿主机上是唯一的. 对于匿名卷 (omitted volumes), 第一个字段被省略.
    • 第二个字段是容器内被挂载文件或者目录的路径
    • 第三个字段是可选的, 比如 ro rw
  • --mount: 由多个键值对组成, 由逗号分隔, 每个键值对由 <key>=<value> 的元组组成. --mount 语法更加详细, 但是键的顺序不重要, 这个标志的值也更容易理解.
    • 挂载的类型 type, 可以是 bind, volume 或者 tmpfs. 此处讨论卷, 所以 type 永远为 volume.
    • 挂载的来源 source. 对于具名卷来说是卷名, 对于匿名卷来说该字段被省略. 可以指定为 source 或者 src.
    • 挂载的目标 destination , 是容器内被挂载文件或者目录的路径. 可以被指定为 destnation, dest, target
    • 只读可选选项 readonly, 这个选项会使卷以只读的方式挂载到容器中.
    • volume-opt 选项, 可以被多次指定, 采用由选项名和值组成的键值对.
-v--mount 的不同

和绑定挂载不同, 卷中的所有选项都可以用于 --mount-v 标志.

当卷与服务一起使用时, 支持 --mount.

创建和管理卷

与绑定挂载不同, 在容器外可以创建和管理卷.

创建一个卷:

代码语言:javascript
复制
docker volume create my-vol

列出所有的卷:

代码语言:javascript
复制
docker volume ls
代码语言:javascript
复制
local			my-vol

查看某个卷的元数据:

代码语言:javascript
复制
docker volume inspect my-vol
代码语言:javascript
复制
[
    {
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
        "Name": "my-vol",
        "Options": {},
        "Scope": "local"
    }
]

删除一个卷:

代码语言:javascript
复制
docker volume rm my-vol

启动一个带有卷的容器

启动容器时如果指定的卷不存在, Docker 会自动创建这个卷. 下面的例子将卷 myvol2 挂载到了容器内的 /app/目录.

-v--mount 在示例中的结果相同, 选择其中一种运行.

  • --mount
  • -v
代码语言:javascript
复制
docker run -d \
  --name devtest \
  --mount source=myvol2,target=/app \
  nginx:latest
代码语言:javascript
复制
docker run -d \
  --name devtest \
  -v myvol2:/app \
  nginx:latest

使用 docker inspect devtest 来确认卷被正确地创建和挂载了, 看下面的 Mounts 部分:

代码语言:javascript
复制
"Mounts": [
    {
        "Type": "volume",
        "Name": "myvol2",
        "Source": "/var/lib/docker/volumes/myvol2/_data",
        "Destination": "/app",
        "Driver": "local",
        "Mode": "",
        "RW": true,
        "Propagation": ""
    }
]

这表明挂载的是一个卷, 显示了正确的源和目标, 并且挂载是可读可写的.

停止容器并移除卷. 移除卷是单独的步骤:

代码语言:javascript
复制
docker container stop devtest

docker container rm devtest

docker volume rm myvol2

使用只读卷

对于一些开发应用程序, 容器需要写入卷, 以便将变化传回宿主机. 其他时候, 容器只需要读取数据. 记住多个容器可以挂载同一个卷, 并单独设置每个容器的读写权限.

  • --mount
  • -v
代码语言:javascript
复制
docker run -d \
  --name=nginxtest \
  --mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \
  nginx:latest
代码语言:javascript
复制
docker run -d \
  --name=nginxtest \
  -v nginx-vol:/usr/share/nginx/html:ro \
  nginx:latest

查看元数据 docker inspect nginxtesMounts 部分:

代码语言:javascript
复制
"Mounts": [
    {
        "Type": "volume",
        "Name": "nginx-vol",
        "Source": "/var/lib/docker/volumes/nginx-vol/_data",
        "Destination": "/usr/share/nginx/html",
        "Driver": "local",
        "Mode": "",
        "RW": false,
        "Propagation": ""
    }
],

停止容器并移除卷:

代码语言:javascript
复制
docker container stop nginxtest

docker container rm nginxtest

docker volume rm nginx-vol

数据卷容器

通过数据卷容器来共享数据. --volumes-from 可以从其他已经挂载卷的容器挂载数据卷, 但不可对挂载位置, 读写权限进行修改. 同一个容器可以指定多个 --volumes-from.

代码语言:javascript
复制
docker run -d -v /app --name test nginx		# 创建数据卷容器

docker run -d --volumes-from test --name test01 nginx	

备份, 恢复或迁移数据卷

使用 --volumes-from. 略

Dockerfile

Dockerfile 是用来构建 docker 镜像的构建文件, 里面写脚本. 每个命令都是镜像的一层

例子:

代码语言:javascript
复制
FROM centos

VOLUME ["/volume01","/volume02"]		#  创建两个匿名的数据卷挂载到 volume01 和 volume0

CMD echo "---end---"					# 打印一些信息

基础知识

  1. 每个保留关键字(指令) 都必须是大写字母.
  2. 执行从上到下顺序执行.
  3. # 表示注释,
  4. 每一个指令都会创建并提交一个新的镜像层.

Dockerfiler 指令

代码语言:javascript
复制
FROM ImageName			 # 指定基础镜像
MAINTAINER <name>		 # 维护者,已过时,应使用 LABEL
RUN <command>			 # 镜像构建的时候运行的命令
COPY [--chown=<user>:<group>] <src>... <dest>	# 官方推荐使用,类似于 ADD
ADD						 # COPY 文件,自动解压 tar
WORKDIR /path/to/workdir # 制定当前的工作目录
VOLUME ["/data"]		 # 设置卷,挂载到容器目录,可以用 -v 修改挂载点
EXPOSE <port> [<port>/<protocol>...] # 暴露端口,随机映射 -P 会用到此处指定的端口
CMD <command> 			 # 容器启动时运行的命令
ENTRYPOINT <command>     # 容器启动时运行的命令
ONBUILD <command>		 # 本次不执行.当该镜像被 FROM 时执行
ENV <key> <value>
ENV <key>=<value1> <key2>=<value2> # 指定环境变量

CMDENTRYPOINT 的不同:

CMD 的具体用法:

代码语言:javascript
复制
CMD <command> 						# 执行 shell 命令
CMD ["<command>","<param1>","<param2>",...] # 推荐写法
CMD ["<param1>","<param2>",...] 	# 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数

dockerfile 中存在多个 CMD 时,只会执行最后一个.可以被 docker run 的命令行参数覆盖.

ENTRYPOINT 的具体用法:

代码语言:javascript
复制
ENTRYPOINT ["<executeable>","<param1>","<param2>",...]

CMD 类似,但是不会被 docker run 的命令行参数覆盖,而是会将 docker run 的命令行参数传给 ENTRYPOINT .可以与 CMD 搭配使用.

举个例子:

代码语言:javascript
复制
FROM nginx

ENTRYPOINT ["nginx", "-c"]
CMD ["/etc/nginx/nginx.conf"]

不传参运行

代码语言:javascript
复制
docker run nginx:test

容器内执行

代码语言:javascript
复制
nginx -c /etc/nginx/nginx.conf

传参执行

代码语言:javascript
复制
docker run nginx:test -c /etc/nginx/new.conf

容器内执行

代码语言:javascript
复制
nginx -c /etc/nginx/n.conf

写好 dockerfile 后,用 docker build 构建一个叫做 my-centos 的镜像:

代码语言:javascript
复制
docker build -f Dockerfile -t my-centos:0.1 .

一个具体的 Dockerfile

代码语言:javascript
复制
FROM centos
MAINTAINER rikka@rikka.com

COPY README.md /usr/local/README.md

ADD ./jdk-8u301-linux-x64.tar.gz /usr/local/
ADD ./apache-tomcat-9.0.52.tar.gz /usr/local/


RUN yum -y install vim

ENV MYPATH /usr/local
ENV JAVA_HOME /usr/local/jdk1.8.0_301
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.52
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.52
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

WORKDIR $MYPATH

EXPOSE 8080

CMD $MYPATH/apache-tomcat-9.0.52/bin/startup.sh && tail -F $MYPATH/apache-tomcat-9.0.52/logs/catalina.out
代码语言:javascript
复制
docker build -t mytomcat:0.1			# 构建镜像
docker run -d -p 8080:8080 --name tomcat -v test:/usr/local/ apache-tomcat-9.0.52/webapps/test mytomcat:0.1	       # 运行容器

Docker 自动创建一个叫做 test 的 volume 挂载到容器内的 test 目录, 在 test 内放入 web 项目即可通过 ip:8080 访问.

Docker 小结

Docker 网络

问题:宿主机是否可以 ping 通容器内 eth0 的 ip?容器之间能 ping 通吗

答:都可以, 试一下就知道

每启动一个容器, docker 就会给容器分配一个 ip, 只要安装了 docker, 就会有一个网卡 docker0 桥接模式, 使用 veth-pair 技术.

veth-pair 是成对出现的一种虚拟网络设备接口, 一端连着网络协议栈, 一端彼此相连. 它充当一个桥梁, 连接各种虚拟设备

我知道这里说得很简略, 但现在不是深入了解 docker 网络的时候, 仅仅是做个了解

过时的: 在 docker run 的时候指定 --link, 即可将指定容器的容器名及其 ip 写入新容器的 hosts, 这样 ping 容器名 就可以 ping 通.

现在应该使用 自定义网络

自定义网络

查看所有的 docker 网络

代码语言:javascript
复制
dockr network ls

网络模式

bridge

桥接模式(默认)

none

不配置网络

host

和主机共享网络

container

容器内网络联通(不常用)

创建一个网络, 桥接模式, 用 16 位表示主机号, 默认网关 192.168.0.1, 名称 mynet

代码语言:javascript
复制
docker network create --driver bridge --subnet 192.168.0.0/24 --gateway 192.168.0.1 mynet

inpect

代码语言:javascript
复制
docker network inspect mynet

将服务放在自己的网络中

代码语言:javascript
复制
docker run -d -P --name tomcat-mynet01 --net mynet tomcat

好处:

  • 使用自定义网络在容器内可以直接 ping 另一个容器名
  • 隔离不同服务使用的子网

网络连通

刚才创建了一个 mynet 网络, 使用 mynet 的容器是 ping 不通使用 docker0 的容器的. 所以需要用到 connet.

如, 将 docker0 上的容器 tomcat01连接到 mynet:

代码语言:javascript
复制
docker network connect mynet tomcat01

此后, 容器 tomcat01 同时有两个 ip.

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-08-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Docker 概述
  • Docker 的基本组成
  • Docker 的原理
  • Docker 常用命令
    • 帮助命令
      • 镜像命令
        • 容器命令
          • 练习
            • 可视化
            • Docker 镜像
              • 镜像是什么
                • Docker 的组成
                  • Docker 镜像加载原理
                • 选择 -v 或者 —mount 标志
                  • -v 和 --mount 的不同
                • 创建和管理卷
                  • 启动一个带有卷的容器
                    • 使用只读卷
                      • 数据卷容器
                        • 备份, 恢复或迁移数据卷
                        • Dockerfile
                          • 基础知识
                            • Dockerfiler 指令
                            • Docker 小结
                            • Docker 网络
                              • 自定义网络
                              相关产品与服务
                              容器服务
                              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                              领券
                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档