https://aws.amazon.com/cn/devops/what-is-devops/
https://shanyue.tech/frontend-engineering/docker.html#ci-%E7%8E%AF%E5%A2%83%E4%B8%8B%E7%9A%84%E4%BC%98%E5%8C%96
https://www.shouxicto.com/article/461.html
https://zhuanlan.zhihu.com/p/61897385
https://www.jetbrains.com/zh-cn/teamcity/ci-cd-guide/ci-cd-best-practices/
https://www.infoq.cn/article/kzmji9omdp4zumlug7s1
https://aws.amazon.com/cn/blogs/china/build-your-ci-cd-pipeline-from-scratch-part-1/
https://www.docker.com/products/docker-desktop
pull 将docker镜像库的镜像拉到本地
run 通过镜像生成一个容器启动起来,镜像跟容器的关系就像是 类和实例的关系
一个服务对应一个一个镜像,一个镜像对应多个容器
build:构建,根据已有镜像创建一个新的镜像
run 的时候看本地有没有image,如果有直接创建容器,如果没有从服务器拉取iamge再创建
此时
查看容器信息: docker container inspect id
[
{
"Id": "abe0114e8b01658bad50284adcf7e9493cf5e33b314e4b5bbc65eed3879c75de",
"Created": "2022-03-06T10:11:54.91322921Z",
"Path": "/docker-entrypoint.sh",
"Args": [
"nginx",
"-g",
"daemon off;"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 2024,
"ExitCode": 0,
"Error": "",
"StartedAt": "2022-03-06T10:11:55.178274002Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:adfdb308d623d3d77627216340eb193ca5e41a9c3cb3a7b4f17163a8922f0f17",
"ResolvConfPath": "/var/lib/docker/containers/abe0114e8b01658bad50284adcf7e9493cf5e33b314e4b5bbc65eed3879c75de/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/abe0114e8b01658bad50284adcf7e9493cf5e33b314e4b5bbc65eed3879c75de/hostname",
"HostsPath": "/var/lib/docker/containers/abe0114e8b01658bad50284adcf7e9493cf5e33b314e4b5bbc65eed3879c75de/hosts",
"LogPath": "/var/lib/docker/containers/abe0114e8b01658bad50284adcf7e9493cf5e33b314e4b5bbc65eed3879c75de/abe0114e8b01658bad50284adcf7e9493cf5e33b314e4b5bbc65eed3879c75de-json.log",
"Name": "/silly_wiles",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {
"80/tcp": [
{
"HostIp": "",
"HostPort": "80"
}
]
},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "private",
"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": null,
"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/0c640f4995ff766b608d795b1fed73eb46d4dc3f5b3fd26b52d5fff292953d70-init/diff:/var/lib/docker/overlay2/1edb3b33828503ded89d2b82dee79dc5e25481a3b09131a179cc9b9bf41b2975/diff:/var/lib/docker/overlay2/d2323926613067b4782b6d905e5dd55f22aede06268ff400bf4fdc4835eb984a/diff:/var/lib/docker/overlay2/67b82ecbf8483724b7cfa9a67b25a214c9073e6f73e328ff4664cd3f3a0f2aa1/diff:/var/lib/docker/overlay2/98dd49acfaf0a64c985d9d31bbba8852dc4021bd076e6852125664e186eef7c6/diff:/var/lib/docker/overlay2/8dd01f3333021745ac38b30768155df01846df2505e582f60af4b68d882d92a3/diff:/var/lib/docker/overlay2/6f1b58de92b7e7444cf9502470e33e633ff165f8437bed88269f7fdfc89857d9/diff:/var/lib/docker/overlay2/e9896160dcc88167b5a349d903bd20e850176ce0f78d6b5f45d963899bddbfde/diff:/var/lib/docker/overlay2/07dd1e327c3d83ffe076b3c625d62e84636b4897d6604c030d8a1dc2ea27abb2/diff",
"MergedDir": "/var/lib/docker/overlay2/0c640f4995ff766b608d795b1fed73eb46d4dc3f5b3fd26b52d5fff292953d70/merged",
"UpperDir": "/var/lib/docker/overlay2/0c640f4995ff766b608d795b1fed73eb46d4dc3f5b3fd26b52d5fff292953d70/diff",
"WorkDir": "/var/lib/docker/overlay2/0c640f4995ff766b608d795b1fed73eb46d4dc3f5b3fd26b52d5fff292953d70/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "abe0114e8b01",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"80/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"NGINX_VERSION=1.21.6",
"NJS_VERSION=0.7.2",
"PKG_RELEASE=1"
],
"Cmd": [
"nginx",
"-g",
"daemon off;"
],
"Image": "docker/getting-started",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": [
"/docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {
"maintainer": "NGINX Docker Maintainers \u003cdocker-maint@nginx.com\u003e"
},
"StopSignal": "SIGQUIT"
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "962c3162875467df9deaf46dd8a69f2d555d5ad13a9b41cc671a87886c3a5f7d",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"80/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "80"
}
]
},
"SandboxKey": "/var/run/docker/netns/962c31628754",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "536bc674ca61688d82e3e37e7cf903673d91c3414f2dc5509a73b309b74afaa9",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "3a181220f8ae581fee31ea07cc86836017dc299a8a8a5c04ee889adbb9bd6acc",
"EndpointID": "536bc674ca61688d82e3e37e7cf903673d91c3414f2dc5509a73b309b74afaa9",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
}
}
]
docker container ps 查看目前运行的容器,docker container ps -a 查看全部的容器
IMAGE 表示这个容器是通过哪个镜像生成的,STATUS 表示当前状态,还有创建时间和命令。hello word 容器在执行了命令后自动终止了运行。
-it 命令进入到操作系统中,输出东西,exit 退出
设置环境变量:docker run -it -e name=”leah” centos /bin/bash
查看最新的容器
port 端口映射:每个容器会暴露一个端口,当访问宿主机的 端口的时候就会映射到容器暴露出来的这个端口上去处理,处理完再返给浏览器。
示例:
在容器里用Nginx启动一个80 端口,监听本地8080端口请求并返回处理结果
-d 运行在后台
查看最后一个容器
查看容器里的进程: docker container top cda2b547727e
nginx: master process nginx -g daemon off; 就是后台运行的意思,不要运行退出
查看容器端口映射:docker container port id
相关命令:
docker container attach
附加到正在运行的容器
docker container commit
从容器的更改创建一个新的映像
docker container cp
在容器和本地文件系统之间复制文件/文件夹
docker container create
创建一个新的容器
docker container diff
检查容器文件系统上文件或目录的更改
docker container exec
在运行容器中运行命令
docker container export
将容器的文件系统导出为tar存档
docker container inspect
显示一个或多个容器的详细信息
docker container kill
杀死一个或多个运行容器
docker container logs
获取容器的日志
docker container ls
列出容器
docker container pause
暂停一个或多个容器内的所有进程
docker container port
列出端口映射或容器的特定映射
docker container prune
取出所有停止的容器
docker container rename
重命名容器
docker container restart
重新启动一个或多个容器
docker container rm
删除(移除)一个或多个容器
docker container run
在新容器中运行命令
docker container start
启动一个或多个停止的容器
docker container stats
显示容器的实时流资源使用统计信息
docker container stop
停止一个或多个运行容器
docker container top
显示容器的正在运行的进程
docker container unpause
取消暂停一个或多个容器内的所有流程
docker container update
更新一个或多个容器的配置
docker container wait
阻止一个或多个容器停止,然后打印退出代码
通过命令操作容器很繁琐、很容易出错,所以就有了dockerfile
什么是 Dockerfile?
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
使用 Dockerfile 定制镜像
这里仅讲解如何运行 Dockerfile 文件来定制一个镜像,具体 Dockerfile 文件内指令详解,将在下一节中介绍,这里你只要知道构建的流程即可。
1、下面以定制一个 nginx 镜像(构建好的镜像内会有一个 /usr/share/nginx/html/index.html 文件)
这个node_modules 是要继承的镜像的node_modules
run 在编译镜像的时候执行的
cmd 在启动容器的时候执行的
- CMD 在docker run 时运行。
- RUN 是在 docker build。
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
# 镜像从那里来
FROM harbor2.corp.shiqiao.com/public/nginx:1.20.1
LABEL Maintainer="xxx"
# ARG 设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。$PROJECT_NAME
# 与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
ARG PROJECT_NAME
# 拷贝文件或目录到容器中,如果是URL或压缩包便会自动下载或自动解压
ADD $PROJECT_NAME/ /usr/share/nginx/html/
ADD nginx.conf /etc/nginx/nginx.conf
# 构建镜像执行的命令,每一次RUN都会构建一层
RUN mkdir -p /var/log/nginx && chown nginx.nginx -R /var/log/nginx /usr/share/nginx/html/
# 镜像从那里来
FROM harbor2.corp.shiqiao.com/public/centos-node:v14.18.0
LABEL Maintainer="xxx"
# ARG 设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。$PROJECT_NAME
# 与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
ARG PROJECT_NAME
# 构建镜像时运行的指令
RUN mkdir /data/$PROJECT_NAME
# 拷贝文件或目录到容器中,如果是URL或压缩包便会自动下载或自动解压
ADD $PROJECT_NAME/ /data/$PROJECT_NAME
# WORKDIR 为 RUN、CMD、ENTRYPOINT、COPY 和 ADD 设置工作目录,就是切换目录
WORKDIR /data/$PROJECT_NAME
# 声明容器的服务端口(仅仅是声明)
EXPOSE 3000
# 类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
ENTRYPOINT ["pnpm","run","start"]
dockerfile 的命令摘要
- FROM- 镜像从那里来
- MAINTAINER- 镜像维护者信息
- RUN- 构建镜像执行的命令,每一次RUN都会构建一层
- CMD- 容器启动的命令,如果有多个则以最后一个为准,也可以为ENTRYPOINT提供参数
- VOLUME- 定义数据卷,如果没有定义则使用默认
- USER- 指定后续执行的用户组和用户
- WORKDIR- 切换当前执行的工作目录
- HEALTHCHECH- 健康检测指令
- ARG- 变量属性值,但不在容器内部起作用
- EXPOSE- 暴露端口
- ENV- 变量属性值,容器内部也会起作用
- ADD- 添加文件,如果是压缩文件也解压
- COPY- 添加文件,以复制的形式
- ENTRYPOINT- 容器进入时执行的命令
自定义的网络内部会自带一个DNS服务器,让我们可以通过容器名字和ID 来访问对象的容器
在网络中Ping是一个十分好用的TCP/IP工具。它主要的功能是用来检测网络的连通情况和分析网络速度。
docker-compose项目是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
使用 compose 的最大优点是你只需在一个文件中定义自己的应用程序栈(即应用程序需要用到的所有服务),然后把这个 YAML 文件放在项目的根目录下,与源码一起受版本控制。其他人只需 clone 你的项目源码之后就可以快速启动服务。
通常适用于项目所需运行环境(对应多个docker容器)较多的场景,例如同时依赖于nodejs、mysql、mongodb、redis等。
这里放下docker-compose.yml文件:
version: '3'
services:
admin-fe:
build:
context: .
dockerfile: Dockerfile
image: admin-fe # 引用官网 nginx 镜像
container_name: admin-fe
ports:
- 8085:80 # 宿主机可以用 127.0.0.1:8085 即可连接容器中的数据库
基于上文的Dockerfile创建镜像,端口映射是8085:80,这里的8085是宿主机端口,80对应的是nginx暴露的 80 端口
- 构建容器:docker-compose build
- 启动所有服务器:docker-compose up -d(后台启动)
- 停止所有服务:docker-compose down
- 查看服务:docker-compose ps
为什么需要compose
访问8081 的时候显示front,访问 8082 的时候显示backend
nodejs:
build:
context: ./node # 构建 node 目录 他会去 node 下面寻找 Dockerfile
ports:
- 127.0.0.1:7001:7001 # 映射 7001
volumes: // 指定数据卷
- ./node/Microservice:/app/Microservice # 项目文件映射
- node_modules:/app/Microservice/node_modules # 单独处理 node_modules
restart: always
depends_on: // 依赖,谁先起再起他
- mongo
networks:
- my-network
Nginx配置文件:conf.d
监听 80 端口
服务名: localhost 或者 ip
访问 / 就找静态文件 public
访问 /api 就交给node服务
web server.js
创建镜像时环境变量提供的参数