Docker命令学习

 


Docker 安装

docker安装

见官网: Install Docker Engine on CentOS | Docker Documentation

安装

# 1. 卸载老版本软件
sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
# 2. 安装相关&设置repository
sudo yum install -y yum-utils
sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
# 3. 安装docker
sudo yum install docker-ce docker-ce-cli containerd.io

# 4. 启动
systemctl start docker
# 5. 设置开机启动
systemctl enable docker
# 6. helloworld
docker run hello-world

阿里云镜像加速

# 登陆阿里云 -> 弹性计算-> 容器镜像服务-> 镜像工具-> 镜像加速器

Docker的常用命令

帮助命令

docker version   # 显示docker版本信息
docker info      # 显示docker的系统信息,包括镜像和容器的数量
docker 命令 --help         # 帮助命令

docker的帮助文档: Docker run reference | Docker Documentation

镜像命令

1. docker images # 查看当前主机的所有镜像

"""
> docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
hello-world   latest    d1165f221234   2 months ago   13.3kB
# 镜像的仓库源  标签       镜像id        创建的时间      镜像的大小
"""

docker images -a   # 显示所有的镜像
docker images -q   # 只列出镜像的id

2. docker search 镜像名 # 搜索镜像

"""
> docker search mysql 

"""
docker search --filter=STARS=3000   # 搜索出来的镜像是stars大于3000

3. docker pull 镜像名 # 下载镜像,默认latest

"""
> docker pull mysql 

"""
docker pull mysql[:tag]   # 可以加tag版本号
docker pull mysql:5.7    # 下载5.7版本的mysql

4. docker rmi -f 镜像名(或镜像id) # 删除镜像

"""
docker rmi -f 镜像id   # 删除指定的镜像
docker rmi -f 镜像id 镜像id2 镜像id3  # 删除多个镜像id
docker rmi -f $(docker images -aq)  # 删除所有镜像
"""

容器命令

1. 新建容器并启动

docker run [可选参数] image

参数:
 --name="myname"  # 容器名,用于区分容器
 -d    # 后台方式运行
 -it   # 使用交互方式运行,进入容器查看内容
 -p    # 指定容器的端口
 	-p 主机端口:容器端口(常用)
 	-p 容器端口
 -P    # 随机指定端口
例如:
	docker run -it centos /bin/bash

2. 列出正在运行的容器

docker ps # 列出正在运行的容器
docker ps -a # 列出运行的+已运行结束的所有容器
docker ps -n=3  # 显示最近运行的几个容器
docker ps -q  # 只显示容器的id

3. 退出容器

exit   # 停止容器并退出
ctrl + p +q  # 容器不停止退出

4. 删除容器

docker rm 容器id  # 删除指定的容器,不能删除正在运行的容器
docker rm -f $(docker ps -aq)  # 删除所有容器
docker ps -a -q | xargs docker rm  # 删除所有容器

5. 启动和停止容器的操作

docker start 容器id
docker restart 容器id
docker stop 容器id
docker kill 容器id  # 强制停止一个容器

容器常用其他命令

1. 后台启动容器

docker run -d centos

# 问题:通过docker ps查看发现centos停止了
原因:docker容器使用后台运行,就必须要一个前台进程,docker发现没有应用会自动停止,例如nginx发现没有提供服务,会立刻结束了

2. 查看日志

docker logs [参数] 容器id

参数:
docker logs -tf 容器id   # 显示日志, t为时间戳,f为follow 
docker logs --tail number 容器id # 显示日志条数

3. 查看容器中的进程信息

docker top 容器id

4. 查看镜像【或容器】的元数据

docker inspect 容器id/镜像

5. 进入当前正在运行的容器

docker exec -it 容器id /bin/bash  # 进入容器后开启一个新的终端

docker attach 容器id  # 进入当前正在打开的容器终端,不会打开新的终端

6. 从容器内拷贝文件到本地主机上

docker cp 容器id:容器内的路径  目的主机路径

例如:
	docker ps 容器id:/root/aa.py /home/fanzone/ 

7. 查看cpu的状态

docker stats 容器id

练习实战

1. docker安装nginx

# 1. 搜索镜像
docker search nginx
# 2. 下载镜像
docker pull nginx
# 3. 运行测试
docker run -d --name nginx01 -p 3344:80 nginx

2. 安装tomcat

# 官方提供使用
docker run -it --rm tomcat:9.0  # --rm 用于测试,执行结束自动删除容器

# 自己用还是下载启动运行
docker pull tomcat:9.0
docker run -d --name tomcat01 -p 3355:8080 tomcat:9.0

3. 部署es+kibana

# es暴露的端口很多,如何解决?
# es十分耗内存,如何解决?
# es数据需要放到一个安全目录,如何解决?  # 挂载解决

docker run -d --name es01 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2

# 添加es的内存限制,修改配置文件,-e 环境配置修改
docker run -d --name es01 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2   # 限制内存最小64,最大512

Docker可视化

portainer

是docker的可视化界面的管理工具,提供一个后台面板供我们操作

docker run -d -p 8088:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

Docker镜像讲解

Docker的镜像都是只读的,当容器启动的时候,一个新的可写层被加载到镜像的顶部,这一层就是我们通常说的容器层,容器一下的层为镜像层。

image-20210505225703242

commit提交镜像

docker commit -m "提交的信息" -a="作者" 容器id 目标镜像名[:tag]


# 练习:
docker commit -a='fhz' -m "add apps" 02bed854b8ef my_tomcat11:1.0

容器数据卷

什么是容器数据卷?

如果数据都在容器中,那我们将容器删除,数据会丢失!需求:数据可持久化

MySQL,容器删除,数据丢失,需求:将数据可以存储在本地。

容器之间可以有一个数据共享的技术,Docker容器中产生的数据,同步到本地。

这就是卷技术,目录的挂载,将容器内的目录,挂载到本地主机上。

挂载数据卷

法一: 直接使用命令来挂载 -v

例如:
	docker 	run -it -v 主机目录:容器内目录 mysql
	docker run -it -v C:/Users/ffz:/home centos /bin/bash
好处:
	可以将本地的nginx目录(/usr/share/nginx)与容器内的nginx目录进行挂载,容器会自动同步

法二: 见下Dockerfile

练习安装MySQL

# 1. 获取mysql镜像
docker pull mysql:5.7
# 2. 运行容器,数据挂载
docker run -d -p 3310:3306 -v c:/Users/fanzone/mysql/conf:/etc/mysql/conf.d -v c:/Users/fanzone/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7

# 3. 此时查看容器详细信息
docker inspect mysql01
"""
"Mounts": [
            {
                "Type": "bind",    # bind类型
                "Source": "/data",
                "Destination": "/data",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
"Volumes": null,

"""

# 4. 启动成功之后
mysql -uroot -P 3310 -p

# 5. 本地创建数据库,查看data目录映射的路径是否正常(一个文件夹)
create database test001; 

# 6. 将容器删除,本地数据依然存在,这就实现了本地数据持久化
docker rm mysql01

具名挂载和匿名挂载

# 如何确定是具名挂载还是匿名挂载,还是制定路径挂载
-v 容器内地址    # 匿名挂载, 此时mount type为volume
-v 卷名:容器内路径  # 具名挂载, mount type 为volume
-v /主机路径:/容器路径   # 指定路径挂载,mount type为bind, 在docker volume ls中不会出现


# 1. 匿名挂载(只有容器内的路径)
docker run -d -P --name nginx01 -v /etc/nginx nginx

# 查看
docker volume --help 
# 查看所有的数据卷
docker volume ls
"""  
DRIVER    VOLUME NAME
local     7f60ec2cd7ee435bf1758e6f145ef62419049115a8c4c12b073e409f1f97e8c4
local     493c55040d4b987d5b0e4e292274084b8b54bc279f5d0cf1d14cc1afffa44435
"""
这里就是匿名挂载

# 2. 具名挂载
docker run -d -P --name nginx01 -v mingzi:/etc/nginx nginx    # mingzi为具名

# 查看
docker volume ls
"""
C:\Users\fanzone>docker volume ls
DRIVER    VOLUME NAME
local     7f60ec2cd7ee435bf1758e6f145ef62419049115a8c4c12b073e409f1f97e8c4
local     493c55040d4b987d5b0e4e292274084b8b54bc279f5d0cf1d14cc1afffa44435
local     940f4aa52b7271864588fb1c53a8bb4447e42808b8e13175f06df90394737c42
local     mingzi
"""

# 查看挂载详细位置
docker volume inspect mingzi
docker volume inspect 7f60ec2cd7ee435bf1758e6f145ef62419049115a8c4c12b073e409f1f97e8c4
"""
[
    {
        "CreatedAt": "2021-05-15T22:07:47+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/mingzi/_data",
        "Name": "mingzi",
        "Options": null,
        "Scope": "local"
    }
]
"""

# 通过-v 容器内路径,加ro或rw改变读写权限
ro  readonly    # 只读
rw readwrite    # 可读可写, 默认

docker run -d -P --name nginx01 -v mingzi:/etc/nginx:ro nginx
docker run -d -P --name nginx01 -v mingzi:/etc/nginx:rw nginx

注意:

  • 所有的docker容器内的卷,没有指定目录的情况下都是在/var/lib/docker/volumes/xxx/_data
  • 通过具名挂载,可以方便找到一个卷,大多数情况使用具名挂载

方式二: 使用Dockerfile

dockerfile用于构建docker镜像的构建文件, 通过这个脚本可以生成镜像,镜像是一层一层的,脚本是一个一个命令,每个命令是一层

docker build -f Dockerfile  -t fanhz/centos .   # -f  指定Dockerfile文件, -t => --target 

# Dockerfile,指令都是大写,每个命令就是镜像的一层
FROM centos

VOLUME ["volume01", "volume02"]  # 这里是匿名挂载, 在容器内/volume01 和 /volume02

CMD echo "--------end ------ "

CMD /bin/bash

数据卷容器 ---- 多个容器间数据共享

# centos数据共享

docker run -it --name docker01 -v volumes fanhz/centos:1.0   # 此时docker01要挂载volumes目录,

docker run -it --name docker02 --volumes-from docker01 fanhz/centos:1.0  # docker01就叫数据卷容器
docker run -it --name docker03 --volumes-from docker02 fanhz/centos:1.0  # --volumes-from 数据卷容器   就可以实现数据间共享了,只能共享volumes目录

# 此时如果删除docker01, 则docker02和docker03中数据依然存在
docker rm -f docker01

两个mysql数据同步

# 多个mysql数据同步
docker run -d -P -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7

docker run -d -P -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7

DockerFile

dockerfile用于构建docker镜像的构建文件

构建步骤:

  1. 编写dockerfile文件
  2. docker build 构建为一个镜像
  3. docker run 运行镜像
  4. docker push 发布镜像(dockerhub或阿里云镜像仓库)

Docker的构建过程

基础知识;

  1. 每一个指令必须为大写
  2. 执行从上向下执行
  3. #表示注释
  4. 每一个指令都会创建一个新的镜像层,并提交

image-20210506231202703

dockerfile是面向开发的,以后要发布项目,就编写镜像,编写dockerfile文件

步骤:

  1. Dockerfile: 构建文件,定义一切的步骤,源代码
  2. Dockerimages: 通过Dockerfile构建生成的镜像,最终发布和运行的产品
  3. Docker容器:容器就是镜像运行起来提供服务

指令说明

FROM     # 基础镜像,从这里开始构建
MAINTAINER   # 镜像是谁写的,一般姓名+邮箱
RUN        # docker构建时候需要运行的命令
ADD        # 添加文件,例如tomcat压缩包,可以自动解压(注意:填写路径时构建上下文)
WORKDIR    # 容器启动后,直接到的工作目录,默认为根目录

VOLUME     # 设置容器卷

EXPOSE     # 指定暴露【端口】, EXPOSE指令实际上并不发布端口。它作为构建映像的人员和运行容器的人员之间的文档,通常发布端口在docker run 运行容器时指定-p来publish端口, 或者指定-P来publish所有指定端口。

CMD        # 指定容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT   # 指定容器启动的时候要运行的命令,可以追加命令

ONBUILD    # 当构建一个被继承Dockerfile这个时候会触发这个指令
COPY       # 类似add,将文件拷贝到镜像中(注意:填写路径时构建上下文)

ENV        # 构建时候设置环境变量

练习:安装centos

Docker hub中大多数的镜像都是FROM scratch 开始的

# 创建自己的centos
# Dockerfile文件内容- myDockerfile
"""
FROM centos

MAINTAINER  fanhz<fanhang64@gmail.com>

ENV MYPATH /user/local
WORKDIR $MYPATH       # 运行时候直接到的目录

RUN yum install -y vim
RUN yum install -y net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "___________end_______"
CMD /bin/bash

"""

# 构建镜像
docker build -f myDockerfile -t fanhz/centos:2.0 .

查看构建过程

docker history 镜像

CMD和ENTRYPOINT的区别

# CMD
""" my_cmd_test_dockerfile
FROM centos

CMD ["ls", "-a"]

"""
docker build -f my_cmd_test_dockerfile -t cmd_test:1.0 .
docker run cmd_test

# 想要追加命令,当你想要添加参数时候
docker run cmd_test -l
"""
error 
"""
# 想要追加命令时候,-l 替换了cmd ['ls', '-a']
# 只能这样 docker run cmd_test ls -la


# ENTRYPOINT
"""
FROM centos
ENTRYPOINT ["ls", "-a"]
"""
# 可以直接在命令后面追加,不会替换
docker run entrypint_test -l
"""
ok 
"""

练习Tomcat镜像

步骤:

  1. 准备tomcat压缩包和jdk压缩包

  2. 编写dockerfile文件,官方命名为Dockerfile,当build的时候回会自动找这个文件,不需要-f指定。

    # Dockerfile
    
    FROM centos
    
    MAINTAINER fanhz<xxx@gmail.com>
    
    COPY readme.md /usr/local/readme.txt
    WORKDIR /usr/local
    
    ADD jdk-8u291-linux-x64.tar.gz /usr/local
    ADD apache-tomcat-7.0.109.tar.gz /usr/local
    
    RUN yum -y install vim
    
    ENV MY_PATH /usr/local
    WORKDIR $MY_PATH
    
    ENV JAVA_HOME /usr/local/jdk1.8.0_291
    ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
    ENV CATALINA_HOME /usr/local/apache-tomcat-7.0.109
    ENV CATALINA_BASH /usr/local/apache-tomcat-7.0.109
    ENV PATH %PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
    
    EXPOSE 8080
    
    CMD /usr/local/apache-tomcat-7.0.109/bin/startup.sh && tail -F /usr/local/apache-tomcat-7.0.109/bin/logs/catalina.out
    
  3. 构建镜像

    docker build -t ffz:1.0 .
    
  4. 启动镜像

    docker run -d -p 9090:8080 --name my_tomcat1 -v c:/Users/fanzone/Desktop/code/test_docker/test:/usr/local/apache-tomcat-7.0.109/webapps/test -v c:/Users/fanzone/Desktop/code/test_docker/logs:/usr/local/apache-tomcat-7.0.109/logs diytomcat
    
  5. 访问测试

  6. 发布项目(做了卷挂载,直接在本地test目录部署就行了)

发布自己镜像

1.发送到dockerhub

1. 登陆hub.docker.com
2. 在我们服务器上commit自己镜像
3. 登陆docker
	docker login --help
	docker login -u   # 用户名
	docker login -p   # 密码
	docker login 回车
4. 登陆成功之后可以提交镜像
	docker push + 作者名/镜像名:版本号
	# 报错 An image does not exist locally with the tag: fanhz/hello-world
	# 使用"docker tag"命令重命名镜像
	docker tag 原来镜像id 新的镜像名+版本号 
	docker tag d1165f221234 fanhz/hello-world:1.0
	
5. push发布
   docker push fanhz/hello-world:1.0

2. 发布到阿里云镜像

1. 登陆阿里云
2. 找到容器镜像服务
3. 创建命名空间
4. 创建容器镜像仓库
   创建-》本地仓库
5. 浏览信息
	docker logout   # 退出登陆
	docker login -u fxxx registry.cn-hangzhou.aliyuncs.com
	docker push registry.cn-hangzhou.aliyuncs.com/my_test/my_test11:[镜像版本号]

Docker网络

docker0理解

docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:7f:fc:3a:cb brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:7fff:fefc:3acb/64 scope link 
       valid_lft forever preferred_lft forever

# linux可以ping通docker容器

原理:

  1. 每启动一个docker容器,docker就会为容器分配一个ip,veth-pair技术

  2. 在tomcat1中可以ping通tomcat2容器【容器和容器之间可以通信】

    image-20210512221438636
  3. 所有容器在不指定网络--net的情况下,都是docker0路由,docker会给我们的容器分配一个默认的可用ip。

  4. docker中的所有网络接口都是虚拟的。

--link(不推荐)

# 不用通过地址,直接ping通
docker exec -it tomcat1 ping tomcat2

# 解决办法
docker run -d -P --name tomcat3 --link tomcat2 tomcat 
docker exec -it tomcat3 ping tomcat2   # ping ok
docker exec -it tomcat2 ping tomcat3   # ping error

# 实例
--link=mysql_server:db   #  是告诉当前容器需要使用mysql_server容器,并命名为db。这里db就是mysql_server容器的别名。在后面连接数据库的时候是可以直接使用mysql -h db -uroot -p1234来连接mysql数据库


docker network ls  # 查看当前docker 可使用网络, 默认使用bridge 为docker0
docker network inspect 容器id   # 查看网络信息

# 其实实质:tomcat3在 /etc/hosts 中配置tomcat02
docker exec -it tomcat3 cat /etc/hosts
"""
172.17.0.2	tomcat3 a7f47379aae4
"""

总结: --link 实质在tomcat3中的hosts添加tomcat2的虚拟ip,现在不建议使用--link了。

现在使用自定义网络,不适用docker0(原因:不支持容器名连接)。

自定义网络(推荐 --net)

命令:

docker network ls # 查看当前网络
docker network rm id  # 移除一个或多个网络
docker network inspect id   # 展示一个网络的详细信息
docker network create ...  # 创建一个网络
docker network connect  网络名 容器名   # 连接一个网络 (网络连通)

实例解释:

[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
441c0f846b8f   bridge    bridge    local
ecb7d6b80ad1   host      host      local
b45843327340   none      null      local


bridge:  桥接docker,默认
none: 不配置网络
host: 和宿主机共享网络
container: 容器网络连通,(用得少,局限大)

测试:(推荐使用 docker network create)

docker run -d -P --name tomcat01 --net bridge tomcat  # 平时在直接执行docker run命令的时候,默认有--net bridge 参数

# 自定义网络,(创建网络)
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 my_net

"""
--driver bridge   # 桥接,--driver参数写死
subnet 子网地址
gateway 网关
"""

# 创建两个my_net容器
docker run -d -P --name tomcat-net-01 --net my_net tomcat
docker run -d -P --name tomcat-net-02 --net my_net tomcat

# 可以【相互】ping通
docker exec -it tomcat-net-01 ping tomcat-net-02  # ping ok  反之ok

好处:

  • redis和mysql集群,不同的集群对应不同的网络,互相隔离。

网络连通

问题: 比如mysql集群网络bridge(172.17.0.0/16) 而redis集群在另一个网络my_net(192.168.10.0),如何连通两个不同网段的容器。

image-20210515232625580

# 解决办法  网络连通, 网卡和网卡不能连通,容器可以和my_net连通,就是在容器中又新增一个ip
docker network connet my_net tomcat01  # 之前的tomcat01网络在默认的bridge

# 连通之后就是将tomcat01添加到mynet网络中
docker network inspect mynet
"""
"Containers": {
            "3f631dcfb8a7415a215afca9cf83df8e150687fcb47e5eca05d115145814c7de": {
                "Name": "tomcat-net-01",
                "EndpointID": "00345e1985cfac6ac0f759ea7d26eac90f32563b6d3bd1fab3cf98a70e1bab72",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            },
            "f50a8422bdc5a8f212e66c5ff026d52e8e19da7a3ceb2b4b56a1aabc677dbc70": {
                "Name": "tomcat-net-02",
                "EndpointID": "bf7194fdb79fb25e6e69de891f2ff588d6ac8e6c832e40c975b1a5c2aceedd4c",
                "MacAddress": "02:42:c0:a8:00:03",
                "IPv4Address": "192.168.0.3/16",
                "IPv6Address": ""
            },
            "f549c3ae03262fb278fdd653b310ff41b509c1c7219ec8349db9c42edd460b81": {
                "Name": "tomcat01",
                "EndpointID": "3c5a7ce3ae7335b1e7b87f72340788b0c32d5ff6636aa9b73011c85b10a06beb",
                "MacAddress": "02:42:c0:a8:00:04",
                "IPv4Address": "192.168.0.4/16",
                "IPv6Address": ""
            }
        },
"""

实战:部署redis集群

image-20210512232130876

实例:

# 创建网络
docker network create --dirver bridge --subnet 192.167.10.0/16 --gateway 192.16710.1 my_redis

# 生成redis的配置文件  redis.sh

for port in $(seq 1 6); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat<< EOF >/mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 192.167.10.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done

# 启动redis 从1-6
docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
-v /mydata/redis/node-1/data:/data \
-v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \
-d --net my_redis --ip 192.167.10.11 redis:5.0.9 redis-server /etc/redis/redis.conf

# 创建集群
docker exec -it redis-1 /bin/bash

redis-cli --cluster create 192.167.10.11:6379 192.167.10.12:6379 192.167.10.13:6379 192.167.10.14:6379 192.167.10.15:6379 192.167.10.16:6379 --cluster-replicas 1  # 然后yes

# 连接集群
redis-cli -c 

# 设置键
set name zs  # 假如写入redis-2
docker stop redis-2
get name  # 切换到备用redis,高可用
posted @   学习记录13  阅读(77)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示