docker
#更新apt包索引
sudo apt-get update
#安装包以允许apt通过 HTTPS 使用存储库
sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
#添加Docker官方的GPG密钥
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
#设置稳定存储库
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
#安装最新版本的Docker Engine和containerd
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
#hello-world 映像验证
sudo docker run hello-world
# 使用脚本安装
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
Dockerfile
“点击展开go语言示例”
# 这个参考示例来自李文周大佬的bluebell项目
FROM golang:alpine AS builder
# 为我们的镜像设置必要的环境变量
ENV GO111MODULE=on \
CGO_ENABLED=0 \
GOOS=linux \
GOARCH=amd64
# 移动到工作目录:/build
WORKDIR /build
# 复制项目中的 go.mod 和 go.sum文件并下载依赖信息
COPY go.mod .
COPY go.sum .
RUN go mod download
# 将代码复制到容器中
COPY . .
# 将我们的代码编译成二进制可执行文件 bluebell_app
RUN go build -o bluebell_app .
###################
# 接下来创建一个小镜像
###################
FROM debian:stretch-slim
COPY ./wait-for.sh /
COPY ./templates /templates
COPY ./static /static
COPY ./conf /conf
# 从builder镜像中把/dist/app 拷贝到当前目录
COPY --from=builder /build/bluebell_app /
RUN set -eux; \
apt-get update; \
apt-get install -y \
--no-install-recommends \
netcat; \
chmod 755 wait-for.sh
# 声明服务端口
EXPOSE 8084
# 需要运行的命令
#ENTRYPOINT ["/bluebell_app", "conf/config.yaml"]
基础知识参考
以下简介节选自docker文档:
- **卷(volumes)**存储在由 Docker管理的主机文件系统(在 Linux 上的/var/lib/docker/volumes/ )。卷完全由 Docker 管理,非 Docker 进程不应修改文件系统的这一部分。卷是在 Docker 中持久化数据的最佳方式。
# 将当前目录的相对路径挂载到/app目录中
volumes:
- ./:/app
docker compose
#单独下载和安装 Compose,不装Docker CLI
#下载 Docker Compose 的当前稳定版本
curl -SL https://github.com/docker/compose/releases/download/v2.7.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
#对二进制文件应用可执行权限
sudo chmod +x /usr/local/bin/docker-compose
#测试安装
docker compose version
# 脚本
curl -fsSL https://get.docker.com -o get-docker.sh && \
sudo sh get-docker.sh && \
docker -v && \
curl -SL https://github.com/docker/compose/releases/download/v2.7.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose && \
sudo chmod +x /usr/local/bin/docker-compose && \
docker compose version
docker-compose.yaml
“点击展开和折叠代码”
version: '3.7'
services:
mysql5.7:
# 镜像名
image: 'mysql:5.7'
# 容器名(以后的控制都通过这个)
container_name: mysql5.7
# 重启策略
restart: always
environment:
# 时区上海
TZ: Asia/Shanghai
# root 密码
MYSQL_ROOT_PASSWORD: root
# 初始化数据库(后续的初始化sql会在这个库执行)
MYSQL_DATABASE: nacos_config
# 初始化用户(不能是root 会报错, 后续需要给新用户赋予权限)
MYSQL_USER: nacos
# 用户密码
MYSQL_PASSWORD: nacos
# 映射端口
ports:
- 3306:3306
volumes:
# 数据挂载
#- /root/mysql/data/:/var/lib/mysql/
# 配置挂载
#- /root/mysql/conf/:/etc/mysql/conf.d/
# 初始化目录挂载,注意此处我只跑了这个挂载,只是为了说明其他配置不应该数据初始化
- /root/mysql/init/:/docker-entrypoint-initdb.d/
command:
# 将mysql8.0默认密码策略 修改为 原先 策略 (mysql8.0对其默认策略做了更改 会导致密码无法匹配)
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
networks:
- proxy
server:
image: ghcr.io/USERNAME/server:master
container_name: server
ports:
- 8082:8082
expose:
- "8082"
depends_on:
- mysql5.7
restart: always
volumes:
- './data:/data/'
networks:
- proxy
web:
image: ghcr.io/USERNAME/web:master
container_name: web
depends_on:
- server
restart: always
ports:
- 3000:3000
expose:
- "3000"
environment:
- VIRTUAL_HOST=example.com
- VIRTUAL_PORT=3000
- LETSENCRYPT_HOST=example.com
- [email protected]
networks:
- proxy
networks:
proxy:
name: nginx-proxy
external: true
“点击展开nginx-proxy代码”
version: '3'
services:
nginx-proxy:
image: jwilder/nginx-proxy
container_name: nginx-proxy
ports:
- "80:80"
- "443:443"
volumes:
- conf:/etc/nginx/conf.d
- vhost:/etc/nginx/vhost.d
- html:/usr/share/nginx/html
- dhparam:/etc/nginx/dhparam
- certs:/etc/nginx/certs:ro
- /var/run/docker.sock:/tmp/docker.sock:ro
restart: always
networks:
- nginxproxy
labels:
- "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy"
letsencrypt:
image: jrcs/letsencrypt-nginx-proxy-companion
container_name: nginx-proxy-le
depends_on:
- nginx-proxy
volumes:
- vhost:/etc/nginx/vhost.d
- html:/usr/share/nginx/html
- dhparam:/etc/nginx/dhparam:ro
- certs:/etc/nginx/certs
- acme:/etc/acme.sh
- /var/run/docker.sock:/var/run/docker.sock:ro
##################
# 由于LETSENCRYPT证书速率限制,可使用ZeroSSL
# 注释掉web服务environment中的:
- LETSENCRYPT_HOST=example.com
- [email protected]
# 需添加如下environment
environment:
- ACME_CA_URI=https://acme.zerossl.com/v2/DV90
- ZEROSSL_API_KEY=
##################
restart: always
networks:
- nginxproxy
volumes:
conf:
vhost:
html:
dhparam:
certs:
acme:
networks:
nginxproxy:
name: nginx-proxy
external: true
基础知识参考
以下简介节选自docker compose文档:
- Compose 中的网络:
Compose默认为您的应用程序设置单个网络。服务中的每个容器都加入默认网络。例如,假设您的应用程序是在一个名为myapp的目录,运行docker-compose up时会创建一个名为myapp_default的网络,服务中使用web和db的配置创建的容器会以web和db的名字加入myapp_default。
但是,当你使用external(外部网络,例如你有2个或多个docker-compose.yml)时,Compose不会创建默认网络,你必须使用docker network create Your_Nerwork
预先创建网络。
注意:文档中示例写法错误,会报错
networks:
proxy:
external:
name: nginx-proxy
应写为:
networks:
proxy:
name: nginx-proxy
external: true
常用命令
Docker命令
docker run [可选参数] imagename #新建并启动容器
--name = "name" 容器取名
-it 交互模式进入容器
-d 后台启动容器 注意:一般后台启动要有前台的应用,否则很可能被守护程序杀掉
-p ip:主机端口:容器端口 #指定端口映射
-v或--volume /卷名称的路径:/容器中的挂载路径
查看:
docker search xxx #搜索dockerhub-镜像
docker images [-a][-q] #列出本地主机的-镜像
-a 显示所有信息
-q 显示所有id
docker ps [-a][-q] #显示当前正在运行的容器
-a 显示当前运行的容器,并显示历史运行过的容器
-q 只显示运行容器的编号
docker logs 容器id #日志
docker top 容器id #查看容器中进程信息
docker inspect 容器id #查看容器的详细信息
操作:
docker build -t tag . #构建标签为tag的镜像
docker pull 镜像:版本号 #拉取-镜像
docker start 容器id #启动容器
docker restart 容器id #重启容器
docker stop 容器id #停止容器
docker kill 容器id #强制停止容器
docker rm 容器id #删除停止状态的容器
docker rm -f 容器id #强制删除容器
docker rmi -f xxx #删除单个-镜像
docker rmi -f $(docker images -aq) #删除所有-镜像
docker stop $(docker ps -a -q) #停止所有容器运行
docker rm $(docker ps -a -q) #删除所有容器
docker network rm $(docker network ls -q) #删除所有network
docker system prune --all --force --volumes #删除一切
exit 容器停止并退出
ctrl+p+q 容器不停止退出
docker exec -it mysql /bin/bash #进入正在执行的mysql容器
docker exec -it 容器名 /bin/sh #进入容器
docker exec -it 容器名 -c "apt-get update && apt-get install -y vim" #进入容器安装vim编辑器
docker exec -it 容器名 -c " apk add --update vim" #进入alpine容器安装vim编辑器
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' [container_name_or_id] #查看容器ip
从容器拷贝内容到主机:
docker cp 容器id: 路径 主机目的路径 #此处不必进入容器,容器可以是关闭的。
Docker-compose命令
docker-compose up -d # 在后台启动服务
docker-compose pull # 拉取
docker-compose -f docker-compose.yml up -d # 指定docker-compose.yml
docker-compose -f docker-compose.yml pull # 指定docker-compose.yml,后同
查看:
docker-compose ps # 查看正在运行中的容器
docker-compose ps -a # 查看所有编排容器,包括已停止的容器
docker-compose images # 列出Compose文件构建的镜像
docker-compose logs # 查看日志
docker-compose logs [serviceName] # 查看某服务的日志
docker-compose logs -f [serviceName] # 查看某服务的实时日志
操作:
docker-compose stop # 停止服务
docker-compose start # 启动已经存在的服务
docker-compose pause [serviceName] # 暂停服务
docker-compose unpause [serviceName] # 恢复服务
docker-compose restart [serviceName] # 重启服务
docker-compose rm # 删除所有(停止状态的)服务容器
docker-compose down # 删除所有容器
docker-compose down --remove-orphans # 删除orphans容器
docker-compose config -q # 验证(docker-compose.yml)文件配置,当配置正确时,不输出任何内容
docker-compose exec --index=1 [serviceName] sh # 进入某服务的第1个容器执行命令
docker-compose --help # 帮助
actions自动化部署前后端分离项目
本文使用github actions + docker compose部署到github container registry(这适用于中小型项目) 附:容器注册平台对比
准备好你的dockerfile
使用github actions
“点击展开示例actions”
on: push: branches: - master workflow_dispatch: env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} jobs: build-and-push-image: runs-on: ubuntu-latest permissions: contents: read packages: write strategy: matrix: node: [ '14' ] steps: - name: Checkout repository uses: actions/checkout@v2 - name: Setup node uses: actions/setup-node@v2 with: node-version: ${{ matrix.node }} - name: npm install run: | cd web #进入前端dockerfile目录 npm install - name: Set up QEMU uses: docker/setup-qemu-action@v1 - uses: docker/setup-buildx-action@v1 id: builder1 - uses: docker/setup-buildx-action@v1 id: builder2 - name: Log in to the Container registry uses: docker/login-action@v1 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} # 用于消毒标签,tag是此动作的重要功能之一,本示例没使用,请见文档 - name: Extract metadata (tags, labels) for Docker id: meta1 uses: docker/metadata-action@v3 with: images: ghcr.io/username/server # images地址 - name: Extract metadata (tags, labels) for Docker id: meta2 uses: docker/metadata-action@v3 with: images: ghcr.io/username/web # images地址 - name: Build and push Docker image 1 uses: docker/build-push-action@v2 with: builder: ${{ steps.builder1.outputs.name }} context: ./server # 服务端dockerfile目录 file: ./server/Dockerfile # 服务端dockerfile push: true tags: ${{ steps.meta1.outputs.tags }} labels: ${{ steps.meta1.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max - name: Build and push Docker image 2 uses: docker/build-push-action@v2 with: builder: ${{ steps.builder2.outputs.name }} context: ./web # 前端dockerfile目录 file: ./web/Dockerfile # 前端dockerfile push: true tags: ${{ steps.meta2.outputs.tags }} labels: ${{ steps.meta2.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max deploy: runs-on: ubuntu-latest needs: build-and-push-image steps: - uses: appleboy/ssh-action@master with: host: ${{ secrets.host }} #仓库设置中添加Secrets:HOST username: root password: ${{ secrets.PASSWORD }} #仓库设置中添加Secrets:PASSWORD port: 22 script: | echo $CR_PAT | docker login ghcr.io -u USERNAME --password-stdin # 用户名 docker-compose -f docker-compose-nginx.yaml -f docker-compose-app.yaml pull # docker-compose名 docker-compose -f docker-compose-nginx.yaml -f docker-compose-app.yaml up -d # docker-compose名 # 此actions许多参数由github自动提供,无需添加,需修改的均已注释
在服务器上完成向 Container registry 验证
具体操作:打开/etc/profile
export CR_PAT=YOUR_TOKEN
source /etc/profile
echo $CR_PAT | docker login ghcr.io -u USERNAME --password-stdin
- 新建docker-compose-app.yaml和代理容器docker-compose-nginx.yaml,示例文档。如有不懂,请多看几遍acme-companion和示例文档。最后,Issues中的实例可能会有帮助。