NetCore在Docker中发布及运行 安装构建镜像启动容器DockerfileDocker-ComposeHttp连接请求过多问题

2020-07-10 10:06:27 浏览数 (1)

之前写过一篇关于Docker的文章,回头看了一眼自己差点没有看明白...最近有时间又仔细研究了一遍(主要是生产环境真的要用到了...),顺便从0学习了一下Linux,踩了不少坑。所以准备再写几篇关于Docker的文章。希望对大家有所帮助。

操作系统为Centos7。项目为asp .netcore webapp。先简单介绍下Docker的安装

安装

代码语言:javascript复制
更新yum包
sudo yum update

安装需要的软件包, yum-util 提供yum-config-manager功能
sudo yum install -y yum-utils device-mapper-persistent-data lvm2

设置Docker的yum源
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

安装Docker 可以用【:版本号】加在后面安装指定的版本,不加就安装最新版本。安装的docker ce,还有个docker ee,是收费版的
sudo yum install docker-ce -y

启动docker
sudo systemctl start docker

使docker服务自动启动
sudo systemctl enable docker

配置镜像加速
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://registry.docker-cn.com"]
}
EOF

重启docker以使用新的镜像地址
sudo systemctl daemon-reload
sudo systemctl restart docker   

构建镜像

这里就按照官方默认的文件及目录结构来构建镜像和容器,方便了解每个命令的含义

假设我的项目名称为:myapp1,Dockerfile文件名称为:Dockerfile_myapp1

目录结构如下

代码语言:javascript复制
/mnt/vda1/code/myapp1
/mnt/vda1/docker/Dockerfile_myapp1

那么构建一个镜像的命令为:

代码语言:javascript复制
docker build [选项] <上下文路径/URL/->

sudo docker build -t myapp1:v1 -f /mnt/vda1/docker/Dockerfile_myapp1 /mnt/vda1/code/myapp1 

-t 指定image的名称和版本,不加:v1 则默认版本为latest

-f 指定Dockerfile文件地址 

/mnt/vda1/code/myapp1为镜像构建的**上下文路径**。所谓的上下文就是说在Dokerfile中可以操作的宿主机器的根路径,超出该路径的文件容器中是访问不到的

启动容器

代码语言:javascript复制
docker run  -d -p 8001:80 myapp1:v1 --myapp2uri=192.168.3.102 --myapp3uri=myapp3
  • -d:指定容器在后台运行
  • -p 8001:80:将容器内的80端口映射到宿主机器上的8001端口
  • 在镜像名称后面的内容则会作为cmd命令传入到程序中

Dockerfile

前面的内容很容易理解,Dockerfile文件照葫芦画瓢也可以写一个能用的,但是一旦涉及到功能需求的变化(比如说做自动构建和发布)就头大了。下面我给Dockerfile中常用到的每一个指令结合上面的项目来做一个详细的介绍

代码语言:javascript复制
#FROM指定基础镜像,也就是说后面的的WorkDir,Run命令都是在这个镜像的基础上执行的
#使用sdk2.2执行项目发布 "AS"可以给该镜像起一个别名,可以为build也可以叫做build1,build2 。。。
FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build

#WORKDIR设置容器内的工作目录。该命令之后的命令都已该目录为根目录进行相关的操作
#当容器启动之后,进入容器会首先进入该目录,容器的根目录为“/“。
WORKDIR /app1

#COPY将宿主机的文件拷贝到容器中去
#第一个“./”为上下文的根目录,上下文的定义在上面的镜像构建中提到过,第二个“./”等于/app1(工作目录)
#此命令将宿主的机的/mnt/vda1/code/myapp1中的所有文件拷贝到容器内的 /app1文件夹下
COPY ./ ./

#RUN 执行命令行命令
#生成项目。这里的dotnet命令使用的是上面的sdk:2.2中的dotnet命令
RUN dotnet build

#发布项目的Release版本到publish文件夹下
#该命令会在sdk2.2生成的容器中的/app1文件夹下执行
RUN dotnet publish -c Release -o publish


#使用runtime2.2运行项目
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS runtime

#设置容器内的工作目录
WORKDIR /app2

#生命准备使用的端口
EXPOSE 80

#--from=build指定这条命令的上下文是build容器,“./”等于/app2
COPY --from=build /app1/publish ./

#设置容器内的时区,如果不设置,默认时区是标准时间比北京时间晚8个小时
RUN echo "Asia/shanghai" > /etc/timezone
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

#程序入口点。这里的dotnet命令使用的是上面的aspnet:2.2中的dotnet命令
#该指令的含义是在容器启动时执行dotnet DockerWeb1.dll命令
#该数组后面还可以继续追加需要的参数,但是为了扩展性及安全性,我们把其余的变量在运行时指定或者在编排工具中指定
ENTRYPOINT ["dotnet", "myapp1.dll"]
#CMD命令同样可以实现ENTERPOINT的功能
#CMD ["dotnet", "myapp1.dll"]

上面的CMD命令被注释掉了,因为CMD很容易被运行时替换掉,拿上面的启动容器的命令来举例:

如果Dockerfile中使用的是CMD而非ENTRYPOINT,那么启动容器的命令就需要写为:

docker run -d -p 8001:80 myapp:v1 dotnet myapp1.dll --myapp2uri=192.168.3.102 --myapp3uri=myapp3

这是因为在myapp:v1后面的命令全是cmd命令,会替换掉Dockerfile中的cmd命令。

不过在执行CMD命令之前会先执行EnterPoint命令。所以实际的执行顺序为:

docker run -d -p 8001:80 myapp:v1 [ENTERPOINT] [CMD]

当然ENTERPOINT也可以被替换,但是并没有替换的必要,因为我们上面的Enterpoint只是指定了一个启动项而已

Dockerfile中的每一个命令都会生成一层镜像,注意是每一个,有时候还会生成多个。。。这个我还没搞明白。 所以上面的一个Dokerfile会生成十四五个image,有一些无用了会被删掉,还有一些会作为中间镜像以的名称存在于image中,可以执行docker images -a命令查看 目前还没有找到自动删除中间层的方法,可以用这个命令进行清理:docker rmi $(docker images --filter dangling=true -q)

Docker-Compose

总是通过那么大一长串命令启动容器和构建镜像实在很麻烦,用docker-compose来管理容器和镜像就会方便很多。

明白了Docker,Docker-compose就容易理解多了。这里只是简单贴一个DockerCompose的配置文件

代码语言:javascript复制
version: "3"
services:
  myapp1:
    #build image的相关操作
    build:
       context: /mnt/vda1/code/myapp1
       dockerfile: /mnt/vda1/docker/Dockerfile_myapp1
    image: myapp1
    restart: always
	#设置容器名称
	container_name: myapp1container
    ports:
      - "8001:80"
	#设置文件夹挂载
    volumes:
      - /mnt/vda1/data/influxexcel:/app/wwwroot/Excels
  myapp2:
    build:
       context: /mnt/vda1/code/myapp2
       dockerfile: /mnt/vda1/docker/Dockerfile_myapp2
    image: myapp2
    restart: always
	container_name: myapp2container
	#CMD参数
    command: --ApiUrl1=myapp1container
    ports:
      - "8002:80"

Http连接请求过多问题

可能报错:Resource temporarily unavailable

修改 sysctl -w net.core.somaxconn=32768 立即生效

vi /etc/sysctl.conf 增加一行 net.core.somaxconn= 32768 sysctl -p 重启生效

0 人点赞