Docker学习笔记(基础篇)
前言
公司绩效里面写了要学习docker,其实平时用也会用,但是没有系统的认知。
考虑到这个东西除了工作外,NAS和单子都有用到,就系统学一学吧。
下面是学习一本叫《第一本Docker书》的笔记。
另外因为成书的时间较早,需要一些外围的资料补充才能跑现在的docker。
目标1:把单子的project打包到docker
目标2:把书看完
嗯,开始吧~
PS1:下面的所有操作都是基于Ubuntu的,缅怀一下已经没了的Centos~
PS2:其实如果是用管理员登入的话就免去好多的sudo了~
一. Docker简介
Docker优点
- 提供一个简单、轻量的建模方式
- 职责的逻辑分离
- 快速、高效的开发生命周期
- 鼓励使用面向服务的架构
Docker架构
- 镜像是构建Docker世界的基石。
- 镜像是Docker生命周期中的构建或打包阶段,而容器则是启动或执行阶段。
- Docker借鉴了标准集装箱的概念,不同的是:集装箱运输货物,而Docker运输软件。
- 镜像是分层的,你可以对其进行迅速的迭代。
二. Docker安装
写在最开始
下面是按照书上所说的做,最后是不行的,想要速度的请跳去这个链接
http://www.jeecms.com/hjdj/872.htm(2022-5-7亲测可行)
或各大搜索引擎搜Ubuntu安装docker
前提条件
#查看内核版本 uname -a #升级linux内核版本 sudo apt-get update sudo apt-get install linux-headers-3.8.0-27-generic linux-image-3.8.0-27-generic linux-headers-3.8.0-27 #更新Ubuntu Precise的启动加载器 sudo update-grub #重启电脑 sudo reboot
其实书本的Ubuntu才12,我的已经不知道多少了,反正就是很高了。
所以上面的代码其实作用不大,但是为什么还要保留下来呢?
可能我觉得安装任何软件之前先确定系统版本是必要步骤吧~
go on~
#检查Device Mapper ls -l /sys/class/misc/device-mapper #如果没装那么 sudo modprobe dm_mod #添加Docker的ATP仓库 sudo sh -c "echo deb https://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list"
开始安装
#检查有没有装curl whereis curl #没有的话就安装他 sudo apt-get -y install curl #添加Docker仓库的GPG密钥 curl -s https://get.docker.io/gpg | sudo apt-key add - #更新APT源 sudo apt-get update #在Ubuntu中安装Docker sudo apt-get install lxc-docker #确认docker已经安装 sudo docker info
好了,按照这个书上说的已经装不了~ 哈哈哈哈哈哈哈
这个时候就去问问度娘咯~ 参考:http://www.jeecms.com/hjdj/872.htm 可以了。
总结如下:
#更新apt软件包索引并安装软件包以允许apt通过HTTPS使用存储库 sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common #添加 Docker 的官方 GPG 密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - #查看当前系统架构 dpkg --print-architecture #根据架构选用以下对应命令执行: #amd64: sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" #armhf: sudo add-apt-repository "deb [arch=armhf] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" #arm64: sudo add-apt-repository "deb [arch=arm64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" #安装DOCKER引擎 sudo apt-get install docker-ce docker-ce-cli containerd.io #列出可用版本 apt-cache madison docker-ce #安装指定版本 sudo apt-get install docker-ce=<版本号> docker-ce-cli=<版本号> containerd.io #我的就是 sudo apt-get install docker-ce=5:20.10.15~3-0~ubuntu-focal docker-ce-cli=5:20.10.15~3-0~ubuntu-focal containerd.io #验证是否安装成功 sudo docker run hello-world
功成~
Docker守护进程
配置docker的访问端口,这个端口设置之后外面的人就可以通过这个端口访问了。
因为这个是没有认证的,这样就很危险了,所以需要这个叫TLS认证的东西去把把关。
当然也可以用防火墙来做~
#配置docker守护进程的网络 export DOCKER_HOST="tcp://0.0.0.0:12345" #查看进程状态 systemctl status docker #关闭进程 systemctl stop docker #开启进程 systemctl start docker
docker的进程管理其实用systemctl就好了,书里面的不知道是啥,反正用不鸟~
三. Docker入门
确保Docker已经就绪
#确保docker就绪 sudo docker info
镜像相关
书本是直接就创建容器了,但是所有容器都是基于镜像的。
所以我觉得有必要在这里补一下镜像的基础部分。
参考网址:https://www.csdn.net/tags/MtTaEgxsOTM3NDItYmxvZwO0O0OO0O0O.html
关于镜像的系统认知请看第四部分~
要点:
- 镜像的话可以去docker hub上面找(https://hub.docker.com/)
- 如果镜像被容器使用了,原则上来说是要先删容器再删镜像的,但是可以用-f来强制删除
#拉取镜像,默认拉最新的,可以直接run,如果没有run会自己拉镜像的 sudo docker pull ubuntu #查看拉取了的所有镜像 sudo docker images --digests #修改镜像库地址 vi /etc/docker/daemon.json #输入 { "registry-mirrors": ["https://3laho3y3.mirror.aliyuncs.com"] } #删除镜像 [OPTIONS] 中 -f 表示强制删除 sudo docker rmi [OPTIONS] IMAGE [IMAGE…] #通过短ID删除,这个代表镜像id以14f6开头的镜像,一般而言,前四位可以唯一标志,如果不可以,docker会提示的 sudo docker rmi 14f6 #通过镜像长ID删除 sudo docker rmi 14f60031763d #通过镜像名删除 sudo docker rmi ubuntu:latest #通过镜像的digest删除 sudo docker rmi > ubuntu@sha256:84c334414e2bfdcae99509a6add166bbb4fa4041dc3fa6af08046a66fed3005f #删除所有叫redis的镜像 sudo docker rmi $(docker images –q redis) #删除所有镜像 sudo docker rmi $(docker images –qa)
创建容器
搞了这么久终于可以创建容器了,要点有:
- 可以使用docker run指令创建容器;
- docker run提供了容器从创建到启动的功能;
- -i 表示保证容器中STDIN是开启的,表示shell接受标准输入;
- -t 表示docker为创建的容器分配一个伪tty终端;
#创建容器 sudo docker run -i -t ubuntu /bin/bash
使用容器
因为安装的是最简的Ubuntu,所以好多包都没有默认装上
#列出所有容器 sudo docker ps -a #列出最后一次运行的容器 sudo docker ps -l #----- 容器内 ----- #查看主机名 hostname #查看容器的host cat /etc/hosts #更新软件库 apt-get update #安装查看网络状态的包 apt-get install -y iproute2 #查看容器接口 ip a #退出容器 exit #或者 ctrl + D #----- 容器内 -----
容器命名
- 命名规则:[a-zA-Z0-9_.-]
- 命名必须唯一
#容器命名 sudo docker run --name test_sys -i -t ubuntu /bin/bash #容器改名 sudo docker rename <旧容器名|旧容器id> <新容器名> #ex:把abc的容器改名为cba sudo docker rename abc cba
启停容器
- 无论停止或者启动都不会进入容器内部;
- stop向容器内发送SIGTERM信号,相当于关机;
- kill向容器内发送SIGKILL信号,相当于断电;
#启动容器 sudo docker start <容器名|容器ID> #重启容器 sudo docker restart <容器名|容器ID> #停止容器 sudo docker stop <容器名|容器ID> #如果想快速停止某个容器,那么: sudo docker kill <容器名|容器ID>
附着到容器
上面的启动或者停止都不会进入容器,如果想再次进入那么就需要:
- 停止的容器附着不了,需要启动了才能附着;
- 附着后如果退出,则容器也会停止运行;
#附着到容器 sudo docker attach <容器名|容器ID>
创建守护式容器(daemonized container)
- 上面那些都是交互式运行的容器(interactive container);
- 守护式容器没有shell,适合运行应用程序和服务;
#创建守护式容器,并且跑一个sh,每5秒输出一个hello world sudo docker run --name test_dc -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 5; done"
查看容器日志
- 进入日志模式之后按 ctrl + c 退出;
#查看日志 sudo docker logs <容器名|容器ID> #跟踪日志 sudo docker logs -f <容器名|容器ID> #加入时间戳 sudo docker logs -ft <容器名|容器ID> #获取最新的1000行 sudo docker logs -ft --tail 1000 <容器名|容器ID>
容器内进程
- 使用exec指令,exec是docker1.3引入的,1.3之前看nsenter指令;
- 相当于直接在容器内执行后面的指令了;
- 退出交互式任务不会停止运行docker;
#查看容器内进程 sudo docker top <容器名|容器ID> #运行容器内进程(后台任务),在etc下新建一个叫test的文件 sudo docker exec -d <容器名|容器ID> touch /etc/test #运行容器内进程(交互式任务) sudo docker exec -t -i <容器名|容器ID> /bin/bash
容器的自重启
--restart的值及含义:
- no 默认策略,在容器退出时不重启容器
- on-failure 在容器非正常退出时(退出状态非0),才会重启容器
- on-failure:n 在容器非正常退出时重启容器,最多重启n次
- always 在容器退出时总是重启容器(挂web服务的时候就比较有用了)
#创建一个自重启的容器 sudo docker run -d --restart=always --name <容器名> <镜像名> #设置一个已经存在的容器自动重启 sudo docker update --restart=always <容器名|容器ID> #当退出代码为非0时才重启 sudo docker update --restart=on-failure <容器名|容器ID> #当退出代码为非0时才重启,并且限制重启次数为5次 sudo docker update --restart=on-failure:5 <容器名|容器ID>
获取容器详情
- /var/lib/docker 放着所有docker的镜像、容器以及容器的配置;
- /var/lib/docker/containers放着容器;
#通过inspect获取更多容器信息 sudo docker inspect <容器名|容器ID> #有选择的取容器信息,比如容器运行状态 sudo docker inspect --format='{{.State.Running}}' <容器名|容器ID>
删除容器
禁术总是留到最后
#删除容器 sudo docker rm <容器名|容器ID> #删除所有容器 sudo docker stop $(docker ps -a -q) sudo docker rm $(docker ps -a -q)
四. Docker镜像和仓库
前言
我也不是很明白为什么先说的容器,再说的镜像~
anyway~
这里就会有对镜像的绝大部分操作了~
是什么Docker镜像
- 简单来说Docker镜像就是一个只读的文件系统
- 以一个叫联合加载技术(union mount)实现叠(套)加(娃)
- 当需要对容器里面的只读系统进行写操作时,会复制一个副本到读写层,原来的只读系统是不会发生变法的,这个叫写时复制(copy on write)
- 感性点说:一个容器只有一个基础镜像,基础镜像里面可以装docker,加载其他镜像(套娃)
列出镜像
- 镜像保存在仓库中,从仓库下载下来;
- 而仓库存在于Registry中,默认的Registry是由Docker公司运营的公共Registry服务,即Docker Hub;
- Docker Registry的代码是开源的,可以运行自己私有的Registry服务;
#列出Docker镜像 sudo docker images #查看docker占用系统空间 docker system df
拉取镜像
- 书本上的pull指令默认会拉所有,但现在的pull默认只拉最新的;
- 镜像下载下来后默认保存在:/var/lib/docker 目录下面;
- 查看仓库中镜像的所有tags -- 浏览器打开:"${Registry地址}/${镜像名}/tags",例子:https://registry.hub.docker.com/v1/repositories/ubuntu/tags;
#默认拉取最新的镜像 sudo docker pull ubuntu #拉取指定tag的镜像 sudo docker pull ubuntu:22.10
查找镜像
- 可以通过docker search指令来查找所有Docker Hub上的公共可用镜像
- 查找回来的内容包括:仓库名、镜像描述、用户评价(stars)、是否官方(Official)、是否构建(Automated,是否走了Docker Hub的构建流程)
#查找镜像 sudo docker search ubuntu
构建镜像
好了,到戏玉了
- 构建docker的两种方法:1. docker commit指令;2. docker build指令 + Dockerfile文件;
- 一般不推荐用docker commit来构建了;
- 一般来说我们不是真正的创建新镜像,而是基于一个基础镜像去构建新镜像;
- 如果想从零开始,参考:https://docs.docker.com/develop/develop-images/baseimages/;
- Docker Hub相当于Git Hub,共有的,上了的话随便一个人都能下载下来看;
#登录Docker Hub sudo docker login
构建镜像-commit
- 当我们运行一个容器的时候(如果不使用卷的话),我们做的任何文件修改都会被记录与容器存储层里。而Docker提供了一个docker commit 的命令,可以将容器的存储层保存下来成为镜像。换句话说,就是在原有镜像的基础上,在叠加上容器的存储层,并构成信的镜像,以后我们运行这个新镜像的时候,就会拥有原有容器最后的文件变化。
- 除了学习之外,docker commit还有一些特殊的应用场合,比如被入侵后保存现场等;
- 如果在安装软件,编译构建,那会有大量的无关内容被添加进来,如果不小心清理,将会导致镜像及其臃肿。
- commit出来的镜像是黑箱镜像,虽然docker diff或许可以得到一点线索,但是远远不到可以确保生成一致镜像的地步。
- 任何修改的结果仅仅是在当前层进行标记,添加,修改,而不会改动上一层。
- 其实我个人觉得commit挺好用的~ 黑盒就黑盒啊~ 让你知道那么多干嘛~ 哈哈哈哈哈哈~
#使用commit创建镜像 sudo docker commit [选项] <容器名|容器ID> [<仓库名>[:<标签>]] #-m:提交描述,--author:作者名,Ex: sudo docker commit -m="加入test.json文件" --author="GSSSL" ubuntu gssl/ubuntu_test_file:test #查看提交记录 sudo docker history <容器名|容器ID> #查看容器的修改记录 sudo docker diff <容器名|容器ID>
导入导出镜像
- 其实镜像还能支持导入导出的,这样初期就可以绕开版本库了;
#镜像导出 sudo docker save -o <镜像导出路径及文件名> <镜像名|镜像ID> #ex: sudo docker save -o /home/gssl/download/test_image.tar ubuntu/latest #镜像导入 sudo docker load --input <镜像导入路径及文件名> #ex: sudo docker load --input /home/gssl/download/test_image.tar
构建镜像-Dockerfile
- Dockerfile 是一个文本文件,其内包含了一条条的 指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
FROM
指定了 基础镜像,因此一个Dockerfile
中FROM
是必备的指令,并且必须是第一条指令。- Docker 还存在一个特殊的镜像,名为
scratch
。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。 - scratch适合不以任何系统为基础,直接将可执行文件复制进镜像。
- RUN指令的执行形式有两种:shell 格式:
RUN <命令>
和 exec 格式:CMD ["可执行文件", "参数1", "参数2"]
- 一个RUN指令就算一层镜像,Union FS 是有最大层数限制的,比如 AUFS,曾经是最大不得超过 42 层,现在是不得超过 127 层。
- 使用
&&
将各个所需命令串联起来,Dockerfile 支持 Shell 类的行尾添加\
的命令换行方式,以及行首#
进行注释的格式。 - 如果发现标准输入的文件格式是
gzip
、bzip2
以及xz
的话,将会使其为上下文压缩包,直接将其展开,将里面视为上下文,并开始构建。
#----- Dockerfile ----- FROM debian:stretch RUN set -x; buildDeps='gcc libc6-dev make wget' \ && apt-get update \ && apt-get install -y $buildDeps \ && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \ && mkdir -p /usr/src/redis \ && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \ && make -C /usr/src/redis \ && make -C /usr/src/redis install \ && rm -rf /var/lib/apt/lists/* \ && rm redis.tar.gz \ && rm -r /usr/src/redis \ && apt-get purge -y --auto-remove $buildDeps #清除缓存 #----- Dockerfile ----- #build镜像 sudo docker build [选项] <镜像名>:<TAG_ID> <上下文路径/URL/-> #ex: sudo docker build -t test_image:1.0 .
Dockerfile 指令
- CMD - 用于指定一个容器启动时要运行的指令;
- CMD - docker run可以覆盖CMD的指令;
- CMD - Dockerfile中只能指定一条CMD指令,若指定多条只执行最后一条;
- ENTRYPOINT - 跟CMD一样,但默认docker run不会覆盖;
- ENTRYPOINT - 如果docker run想覆盖,那么加入--entrypoint即可
- RUN - 指定镜像被构建时要运行的指令;
- WORKDIR - 当从镜像创建一个新容器时,在容器内部设置一个工作目录,ENTRYPOINT、/、CMD都会在这个目录下执行;
- ENV - 在镜像构建过程中设置的环境变量;
- ENV - ENV <变量名> <值>,调用:$<变量名>
- USER - 指定该镜像以什么样的用户去运行;
- USER - docker run时可以用-u覆盖;
- VOLUME - 用来向基于镜像创建的容器添加卷;
- VOLUME - 关于卷有以下几个特性:
- 卷可以再容器间共享和重用;
- 一个容器可以不是必须和其他容器共享卷;
- 对卷的修改是即时生效的;
- 对卷的修改不会对更新镜像产生影响;
- 卷会一直存在直到没有任何容器使用它;
- VOLUME - 可以用来测试容器和内部代码、管理日志、或者处理容器内数据库?
- ADD - 用来将构建环境下的文件和目录复制到镜像中,源是文件夹的话会把文件夹整个拷过去。
- ADD - ADD <源文件|源路径|URL> <目标文件|目标路径>
- ADD - ADD源文件是归档文件(就是压缩包)的话,会自动解压到目标目录,相当于-x的tar指令;
- ADD - 如果目标路径不存在,那么会创建这个全路径;
- ADD - ex: ADD xx.js /opt/app/xx.js #把xx.js写入到xx.js里面
- ADD - ex:ADD xx.tar /opt/app #把xx.tar解压缩到目标目录下
- COPY - 跟ADD类似,但COPY只关心再构建上下文复制本地文件,而不提取或解压。源是文件夹的话会把文件夹下所有内容拷过去;
- COPY - COPY <源文件|源路径|URL> <目标文件|目标路径>
- COPY - 目标目录不在Docker会自动创建目录结构,类似mkdir -p那样
- ONBUILD - 能为镜像添加触发器(trigger)。当一个镜像被用作其他镜像的基础镜像时,该镜像中的触发器将会被执行。
- ONBUILD - 一般跟在FROM之后,触发器后可以跟任何指令。
- ONBUILD - ONBUILD ADD ./app/src
- ONBUILD - 就是ONBUILD指定的操作只会在创建子镜像的时候执行一次,基于这个子镜像做的孙子镜像是不会再执行了
私有仓库
决定在构建镜像之前先把私库给搞好先;
Docker Hub上的镜像都是公家的,如果不想公开,那么就要做一个私有仓库了;
参考以下链接:
https://yeasy.gitbook.io/docker_practice/repository/registry
https://cloud.tencent.com/developer/article/1718368
docker run -d -p 5000:5000 -v /data/my_docker_registry/registry:/var/lib/registry -v /data/my_docker_registry/config.yml:/etc/docker/registry/config.yml --name my_docker_registry registry
要转图形图像方面的学习了,docker就暂时到这里吧~~
其实就差docker-compose、私库部署这两块了~ 后面有时间再补吧~