# Docker笔记
# 01_Docker 是什么
- 一次封装,到处执行
- 基于Linux的高效、敏捷、轻量级容器方案。
# 使用
# 下载镜像
git clone ......./docker_ci.git
# 启动镜像(所有的服务都启动了)
docker-compose up
# 02_Docker安装
# apt升级
sudo apt-get update
# 添加相关软件包
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
software-properties-common
# 下载软件包的合法性,需要添加软件源的 GPG 密钥
curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
# source.list 中添加 Docker 软件源
sudo add-apt-repository \
"deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu \
$(lsb_release -cs) \
stable"
# 安装 Docker CE
sudo apt-get update
sudo apt-get install docker-ce
# 脚本自动安装(不需要)
curl -fsSL get.docker.com -o get-docker.sh
sudo sh get-docker.sh --mirror Aliyun
# 启动 Docker CE
sudo systemctl enable docker
sudo systemctl start docker
# 建立 docker 用户组(附加)
sudo groupadd docker
sudo usermod -aG docker $USER
# Helloworld
docker run hello-world
启动Docker CE时如果报这个错:perl: warning: Setting locale failed. 的解决方案
镜像加速
# /etc/docker/daemon.json
{
"registry-mirrors": [
"https://dockerhub.azk8s.cn",
"https://reg-mirror.qiniu.com"
]
}
# 重启docker服务
sudo systemctl daemon-reload
sudo systemctl restart docker
# 测试一下下载速度
docker pull nginx
# 03_简单Nginx服务
# 拉取nginx镜像
docker pull nginx
# 查看
docker images nginx
# www目录里放一个index.html
mkdir www
echo 'hello docker!!' >> www/index.html
# 用 docker 启动 nginx 镜像
# 参数: 端口映射:-p 8000:80, 目录映射 -v ....
docker run -p 8000:80 -v $PWD/www:usr/share/nginx/html nginx
# 用 docker 启动 nginx 镜像
# 参数: 端口映射:-p 8000:80, 目录映射 -v ...., 守护模式 -d
docker run -p 8000:80 -v $PWD/www:usr/share/nginx/html -d nginx
# 查看docker进程
docker ps
# 查看所有docker进程
docker ps -a
# 停镜像
docker stop [container ID 前3位]
# 启动镜像
docker start [container ID 前3位]
# 进入docker内部的伪终端
docker exec -it [c99] /bin/bash
# 看看刚才映射的目录
cd /usr/share/nginx/html
cat index.html
# 退出docker内部
exit
# 停止并删除列表中的镜像(不是删除镜像本身)
docker stop c99
docker rm c99
# 04_Docker运行过程
镜像 (Image) 面向Docker的只读模板
容器 (Container) 镜像的运行实例
仓库 (Registry) 存储镜像的服务器
# 05_定制镜像
镜像的定制实际就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是Dockerfile。
定制自己的web服务器
# 创建Dockerfile FROM nginx:latest RUN echo '<h1>Hello, Kaikeba!</h1>' > /usr/share/nginx/html/index.html
# 进入Dockfile所在目录,如: cd ~/source/docker/nginx # 定制镜像 docker build -t nginx:kaikeba . # 运行 docker run -p 8000:80 nginx:kaikeba
# 06_定制NodeJS镜像
# 准备好node和npm
# 安装nvm
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
# 查看可安装node版本
nvm ls-remote
# 安装node和npm(最新lts版)
nvm install --lts
# 升级npm
npm i -g npm
# npm换源
npm config set registry https://registry.npm.taobao.org
# npm源还原
npm config set registry https://registry.npmjs.org
# 开发一个简单koa程序
npm init -y
npm i koa -s
vi app.js
// app.js
const Koa = require('koa')
const app = new Koa()
app.use(ctx => {
ctx.body = 'Hello NodeJS !!'
})
app.listen(3000, () => {
console.log('app started at 3000')
})
写入Dockerfile
FROM node:12-alpine
ADD . /app/
WORKDIR /app
RUN npm install
EXPOSE 3000
CMD ["node", "app.js"]
构建镜像
# 定制镜像
docker build -t mynode .
# 启动镜像
docker run -p 3000:3000 mynode
# 07_PM2镜像
# 拷贝一下上节课的node镜像
cp -R node pm2
cd pm2
# .dockerignore
node_modules
// proces.yml
apps:
- script: app.js
instances: 2
watch: true
env:
NODE_ENV: production
# Dockerfile
FROM keymetrics/pm2:latest-alpine
WORKDIR /usr/src/app
ADD . /usr/src/app
RUN npm config set registry https://registry.npm.taobao.org/ && npm i
EXPOSE 3000
# pm2 在 docker 中的命令为 pm2-docker
CMD ["pm2-runtime", "start", "process.yml"]
# 定制镜像
docker build -t mypm2 .
# 启动镜像
docker run -p 3000:3000 -d mypm2
# 08_Docker-compose
# 安装 docker-compose
apt install docker-compose
# 新建 docker-compose
mkdir helloworld && cd helloworld
vi docker-compose.yml
# docker-compose.yml
version: '3.1'
services:
hello-world:
image: hello-world
# 启动 docker-compose
docker-compose up
compose是官方开源项目,负责docker容器集群的快速编排
# docker-compose.yml
# 一次性启动 mongo 和 mongo-express 镜像
version: '3.1'
services:
mongo:
image: mongo
restart: always
ports:
- 27017:27017
mongo-express:
image: mongo-express
restart: always
ports:
- 8000:8081
docker-compose up
# 09_前后端分离
# 免密登录
# 查看我的本机公钥( 还有对应的私钥 id_rsa )
cat ~/.ssh/id_rsa.pub
# 如果没有就生成一对(一路回车即可)
ssh-keygen -t rsa [-C "yourEmail"]
# 把公钥复制到远程主机上(出来一些提示,并要你输入密码后,就成功了。)
ssh-copy-id -i ~/.ssh/id_rsa.pub root@你的IP地址
# 登录
ssh root@你的IP地址
# 给服务器起别名
cd ~/.ssh
touch config
vi config
# config
Host *
UseKeychain yes
Host server1
HostName 148.157.254.111
User root
Host server2
HostName 148.157.254.112
User root
# 用别名登录
ssh server1
# 注意:nodejs的ssh2模块 不能解析 ssh 生成的密钥
# 如果用vscode的deploy插件时报这个错:Cannot parse privateKey: Unsupported key format
# 你需要将公钥转换格式,或重新生成密钥对
# 重新生成
ssh-keygen -m PEM -t rsa
# 转换已有的私钥格式 (推荐,注意先备份)
ssh-keygen -p -m PEM -f ~/.ssh/id_rsa
# 典型的前后分端项目
# 包括4个容器 (app-pm2, mongo, mongo-express, nginx)
# 其中app-pm2需要自己构建
# 其余的直接拉镜像
# docker-compose.yml
version: '3.1'
services:
app-pm2:
container_name: app-pm2
#构建容器
build: ./backend
#直接从git拉去
# build: git@github.com:su37josephxia/docker_ci.git#:backend
# 需要链接本地代码时
# volumes:
# - ./backend:/usr/src/app
ports:
- "3000:3000"
mongo:
image: mongo
restart: always
ports:
- 27017:27017
mongo-express:
image: mongo-express
restart: always
ports:
- 8081:8081
nginx:
restart: always
image: nginx
ports:
- 8091:80
volumes:
- ./nginx/conf.d/:/etc/nginx/conf.d
- ./frontend/dist:/var/www/html/
- ./static/:/static/
# 10_持续集成
git重要技能
# git push 强制提交
git push -f origin master
# 从远程仓库下载最新版本
git fetch --all
# 将本地设为刚获取的最新的内容(强制覆盖)
git reset --hard origin/master
利用webhooks 来持续构建
// webhooks.js
// github的webhooks 中要有同样的配置 ( path: '/webhook', secret: 'myhashsecret')
var http = require('http')
var createHandler = require('github-webhook-handler')
var handler = createHandler({ path: '/webhook', secret: 'myhashsecret' })
http.createServer(function (req, res) {
handler(req, res, function (err) {
res.statusCode = 404
res.end('no such location')
})
}).listen(7777)
handler.on('*', function (event) {
console.log('Received *', event.payload.action);
})
handler.on('error', function (err) {
console.error('Error:', err.message)
})
handler.on('push', function (event) {
console.log('Received a push event for %s to %s',
event.payload.repository.name,
event.payload.ref)
// 分支判断
if(event.payload.ref === 'refs/heads/master'){
console.log('deploy master..')
run_cmd('sh', ['./deploy-dev.sh'], function(text){ console.log(text) });
}
})
handler.on('issues', function (event) {
console.log('Received an issue event for %s action=%s: #%d %s',
event.payload.repository.name,
event.payload.action,
event.payload.issue.number,
event.payload.issue.title)
})
function run_cmd(cmd, args, callback) {
var spawn = require('child_process').spawn;
var child = spawn(cmd, args);
var resp = "";
child.stdout.on('data', function (buffer) { resp += buffer.toString(); });
child.stdout.on('end', function () { callback(resp) });
}
持续构建的布署脚本
#deploy-dev.sh
echo Deploy Project
# docker-compose up -d --force-recreate --build
# 获取最新版代码
git pull
# 强制重新编译容器
docker-compose down
docker-compose up -d --force-recreate --build
# 定制镜像
# docker build -t myapp:pm2 ./backend
# 重启启动容器
# docker stop myapp
# docker rm myapp
# docker run --name myapp -p 3000:3000 -d myapp:pm2
实际经验
- 改前端dist目录,改动可以立即生效,因为不需要构建。
- 改后端server的内容,却不会立即生效,因为没有引发构建,只有改改docker-compose, 才会引发重新构建
# ubuntu 安装 nginx
# 安装nginx
$sudo apt-get install nginx
# 更新源
$sudo apt-get update
# 更新已安装的包
$sudo apt-get upgrade
$sudo /etc/init.d/nginx start # 启动
$sudo /etc/init.d/nginx stop # 停止
$sudo /etc/init.d/nginx restart # 重启
$sudo /etc/init.d/nginx status # 状态
# 查看端口占用
lsof -i:80
# 测试nginx.conf文件
/usr/sbin/nginx -t -c /etc/nginx/nginx.conf
名称 | 目录 |
---|---|
配置文件 | /etc/nginx/nginx.conf |
程序文件 | /usr/sbin/nginx |
日志 | /varlog/nginx |
默认虚拟主机 | /var/www/html |
守护进程程序文件 | /etc/init.d/nginx |