十七、K8s+gitlab+Jenkins建立CI/CD解决方案

一、什么是CI/CD:

CI:可持续集成
CD:可持续交付\可持续部署
具体含义请参考:https://blog.csdn.net/tushanpeipei/article/details/118082462?spm=1001.2014.3001.5501

CI/CD环境流程图:
在这里插入图片描述

二、实验环境总览:

在这里插入图片描述

本次实验仅存在测试部署环境。

实验流程:

步骤1: 程序员将代码编辑完成后推到代码仓库GitLab里;

步骤2: CI Tool Jenkins将Gitlab里的代码代码打包成镜像;

步骤3: Jenkins将镜像推送到镜像仓库Docker Registry;

步骤4: Jenkins在测试环境K8s集群中部署应用;

步骤5: K8s集群在部署应用的镜像从创建的私有镜像仓库Docker Registry中下载。

物理环境图:
在这里插入图片描述

为了节约设备性能,我们将Jenkins、GitLab、Registry三个部分搭建到一个虚拟机(Centos8)上,且已经安装好了docker-ce。

在K8s集群中,有三台虚拟机,一台Master、两台Worker Nodes。

总体来说,实验环境一共用到了四台虚拟机和一台测试使用的物理机(本机)。

准备步骤:
步骤1:在centos8上设置docker的私有仓库源

[root@localhost ~]# cat /usr/lib/systemd/system/docker.service

ExecStart=/usr/bin/dockerd --insecure-registry 192.168.0.166:5000 -H fd:// --containerd=/run/containerd/containerd.sock

在ExecStart=这个位置写上私有仓库的地址和端口号(192.168.0.166:5000)

步骤2:由于Jenkins需要借助其宿主的docker来构建编译和推送,所以还需要在ExecStart=这个位置加上如下的信息

[root@localhost ~]# cat /usr/lib/systemd/system/docker.service

ExecStart=/usr/bin/dockerd --insecure-registry 192.168.0.166:5000 -H tcp://0.0.0.0:2376 -H fd:// --containerd=/run/containerd/containerd.sock

后续Jenkins可以通过其宿主机的2376端口使用docker的相关功能。

步骤3: 重启docker

systemctl daemon-reload ; systemctl restart docker

步骤4: 在centos上下载后续使用所需使用的镜像nginx

docker pull nginx

三、Docker Registey搭建

步骤1: centos8上下载registry镜像

docker pull registry

步骤2: 运行容器

docker run -d --name registry -p 5000:5000 --restart=always -v /myreg:/var/lib/registry registry

registry使用宿主机的5000端口,并将宿主机的目录/myreg映射到了容器的/var/lib/registry中。

步骤3: 查看容器是否正常运行

[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE              COMMAND                  CREATED       STATUS                    PORTS                                                           NAMES
8131b6a2970e   registry:latest    "/entrypoint.sh /etc…"   2 weeks ago   Up 15 minutes             0.0.0.0:5000->5000/tcp   

四、K8s环境搭建:

在这里插入图片描述

篇幅较长,请参考:
https://blog.csdn.net/tushanpeipei/article/details/118395393?spm=1001.2014.3001.5501

注意:为了能够让K8s的worker也能够访问私有仓库,拉取镜像,也需要在2个Worker上设置docker的私有仓库源:

cat /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --insecure-registry 192.168.0.166:5000 -H fd:// --containerd=/run/containerd/containerd.sock

五、Gitlab搭建:

实验环境:Centos8,已经提前安装好Docker。

步骤1:拉取gitlab镜像

docker pull gitlab/gitlab-ce

ce是社区版本,免费。

步骤2:运行gitlab-ce容器
通常会将 GitLab 的配置 (etc) 、 日志 (log) 、数据 (data)放到容器之外, 便于日后升级, 因此请先准备这三个目录。并确保目录存在并且已授予适当的权限。

在系统的根目录执行(存放的路径根据自己随意设置即可)。

mkdir -p /data/gitlab/etc /data/gitlab/log /data/gitlab/data
chmod 777 /data/gitlab/etc /data/gitlab/log /data/gitlab/data

然后创建容器:

docker run -dit --name=gitlab --restart=always -p 8443:443 -p 80:80 -p 222:22 -v /data/gitlab/etc/:/etc/gitlab -v /data/gitlab/log:/var/log/gitlab -v /data/gitlab/data:/var/opt/gitlab --privileged=true gitlab/gitlab-ce

解释:

  1. -d:后台运行
  2. -p:将容器内部端口向外映射
  3. –name:命名容器名称
  4. -v:将容器内数据文件夹或者日志、配置等文件夹挂载到宿主机指定目录
  5. 8443:443:将http:8443映射到外部端口443
  6. 80:80:将web:80映射到外部端口80
  7. 222:22:将ssh:22映射到外部端口222

注意: 如果端口映射冲突可以自行更改端口。

查看容器是否启动:

[root@localhost /]# docker ps
CONTAINER ID   IMAGE              COMMAND                  CREATED         STATUS                            PORTS                                                            NAMES
881d0b875d3a   gitlab/gitlab-ce   "/assets/wrapper"        2 minutes ago   Up 2 minutes (health: starting)   0.0.0.0:80->80/tcp, 0.0.0.0:222->22/tcp, 0.0.0.0:8443->443/tcp   gitlab

步骤3:修改gitlab.rb文件
按上面的方式,gitlab容器运行没问题,但在gitlab上创建项目的时候,生成项目的URL访问地址是按容器的hostname来生成的,也就是容器的id。作为gitlab服务器,我们需要一个固定的URL访问地址,于是需要配置gitlab.rb ,配置http协议所使用的访问地址。

首先需要将gitlab的容器stop一下:

docker stop gitlab

通过vim来编辑相应的配置,:

vim /data/gitlab/etc/gitlab.rb

此文件中的所有信息都是被注释掉的,需要找到如下三行取消注释,并修改其中的内容。

配置http协议所使用的访问地址(宿主机地址),不加端口号默认为80:

external_url 'http://192.168.0.166'  

配置ssh协议所使用的访问地址和端口:

gitlab_rails['gitlab_ssh_host'] = '192.168.0.166'
gitlab_rails['gitlab_shell_ssh_port'] = 222 # 此端口是run时22端口映射的222端口

保存配置文件并退出。

步骤4:修改gitlab.yml文件

vim /data/gitlab/data/gitlab-rails/etc/gitlab.yml

设置host为自己的地址:

 ## GitLab settings
  gitlab:
    ## Web server settings (note: host is the FQDN, do not include http://)
    host: 192.168.0.166
    port: 80
    https: false

步骤5:启动容器,登录检查

docker start gitlab

输入命令后等待一段时间,使用命令docker ps查看容器的状态:

[root@localhost /]# docker ps
CONTAINER ID   IMAGE              COMMAND                  CREATED          STATUS                   PORTS                                                                              NAMES
881d0b875d3a   gitlab/gitlab-ce   "/assets/wrapper"        24 minutes ago   Up 2 minutes (healthy)   0.0.0.                  0:80->80/tcp, 0.0.0.0:222->22/tcp, 0.0.0.0:8443->443/tcp   gitlab

注意STATUS这里一定要是healthy。然后再游览器中输入192.168.0.166这个宿主机地址,进入到gitlab的页面。初次登陆会让你设置root账号的密码,并且需要满足一定的安全性要求,然后就可以通过root和你设置的密码进行登录。
在这里插入图片描述
步骤6: 创建gitlab项目
选择创建空白的项目:
在这里插入图片描述
设置项目名称并创建:
在这里插入图片描述
完成后,我们可以看到这里的提示:点击添加SSH Key
在这里插入图片描述
返回centos8,创建公钥和私钥:

[root@localhost ~]# ssh-keygen -N ""
[root@localhost ~]# ls .ssh
id_rsa  id_rsa.pub  known_hosts

查看公钥信息,然后复制到gitlab的Key中。

cat .ssh/id_rsa.pub

在这里插入图片描述
完成了这一步后,我们就可以用ssh连接到gitlab上。

步骤7:初始化项目
重新回到我们的项目页面:
在这里插入图片描述
复制内容到我们的centos8上,设置一些变量:(没有安装git的话,需要提前安装yum install git -y)

然后根据第二步,克隆test_project:

git clone ssh://git@192.168.0.166:222/root/test_project.git

根据第三步提示,进入克隆的目录,创建README.md介绍文件,并push到gitlab上:

cd test_project
touch README.md
git add README.md
git commit -m "add README"
git push -u origin master

在这个步骤中,如果第一次创git,提示报错的话,需要按照其提示的信息操作。完成上述步骤后,我们就将创建的README.md push到了gitlab的项目中,可以查看:
在这里插入图片描述
注意:

到目前为止,gitlab的操作已经完成一大半,最后需要等Jenkins搭建完成后,连读Jenkins做操作。

六、Jenkins搭建:

步骤1:Centos8上下载Jenkins镜像

docker pull jenkins/jenkins

步骤2:创建目录,在本地创建一个数据卷挂载docker容器中的数据卷

mkdir /jenkins ; chown 1000.1000 /jenkins

需要修改下目录权限,因为当映射本地数据卷时,/jenkins目录的拥有者为root用户,而容器中jenkins用户的 uid 为 1000。

步骤3:创建Jenkins容器

docker run -dit -p 8080:8080 -p 50000:50000 --name jenkins --privileged=true --restart=always -v /jenkins:/var/jenkins_home jenkins/jenkins

步骤4:修改Jenkins信息
当通过游览器访问如下页面后(8080端口),等待一段时间,就可以停止掉Jenkins了:在这里插入图片描述

docker stop Jenkins

修改如下文件的设置,将更新Jenkins,安装Jenkins插件的地址修改为国内的源:

[root@localhost ~]# cat /jenkins/hudson.model.UpdateCenter.xml
<?xml version='1.1' encoding='UTF-8'?>
<sites>
  <site>
    <id>default</id>
    <url>http://mirrors.tuna.tsinghua.edu.cn/jenkins</url>
  </site>
</sites>

修改的第二个地址:vim /jenkins/updates/default.json;将第一行的www.google.com修改为www.baidu.com。

步骤5: 重新启动jenkins

docker start jenkins

步骤6:访问jenkins,并拷贝密码登陆
在这里插入图片描述
容器内的目录为/var/jenkins_home/secrets/initiaAdminPassword,对应的宿主机目录如下:

cat /jenkins/secrets/initialAdminPassword

拷贝密码后登陆jenkins,然后选择安装推荐的插件。这个时候就会自动去安装,当插件都安装成功后,会看到如下的页面:
在这里插入图片描述
填写信息并创建管理员用户。创建完成后,我们就进入了jenkins的主页:
在这里插入图片描述
步骤7:连接jenkins和宿主机的docker,让jenkins能够构建镜像,发布到镜像仓库中

按照如下的步骤进行:安装docker插件
在这里插入图片描述
在这里插入图片描述
如果不能直接安装,则选择install without restart,然后点击已安装,就可以找到对应的插件了:
在这里插入图片描述
然后按照以下的配置去连接到宿主机的docker上:
在这里插入图片描述
在这里插入图片描述
选择docker:
在这里插入图片描述
然后选择设置详细信息:按照如下的信息进行连接。
在这里插入图片描述
继续操作:
在这里插入图片描述
找到docker build一栏,然后测试连通性,并保存。
在这里插入图片描述
完成这部以后,jenkins就能连接到宿主机,做镜像打包等操作了。

步骤8: 在jenkins中设置gitlab连接的安全参数
在这里插入图片描述
设置授权策略并保存:

在这里插入图片描述
返回到Centos8中去关闭CSRF,进入容器中:

docker exec -u root -it jenkins bash

如果容器里面协议vi或者vim,则需要下载:

apt-get update
apt-get install vim

修改文件,大概在第37行,添加如下内容:

vim /usr/local/bin/jenkins.sh

修改的内容如下:

 exec java -Duser.home="$JENKINS_HOME" -Dhudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true  "${java_opts_array[@]}" -jar ${JENKINS_WAR} "${jenkins_opts_array[@]}" "$@"

保存后退出,重启jenkins。完成后重新登陆jenkins,然后再安全设置里面可以看到CSRF已经被关闭掉了。
在这里插入图片描述

步骤9: 在jenkins中下载k8s客户端(能够在K8s环境下部署)

在Centos8上:注意版本号和k8s集群的要相同

curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/linux/amd64/kubectl

获取K8s的登陆文件kc1,如何获取可以查看https://blog.csdn.net/tushanpeipei/article/details/118662027?spm=1001.2014.3001.5501,记得还需要对对应用户进行授权(给了cluster-admin权限)。

然后拷贝kc1和kubectl到容器中:

[root@localhost ~]# docker cp kc1 jenkins:/
[root@localhost ~]# docker cp kubectl jenkins:/

进入jenkins容器,给kubectl加上权限:

[root@localhost ~]# docker exec -u root -it jenkins bash
root@1703fb001ac9:/# chmod +x ./kubectl
root@1703fb001ac9:/# chmod 644 kc1

查看是否能够登陆k8s,并进行管理:

root@1703fb001ac9:/# ./kubectl --kubeconfig=kc1 get nodes -n security
NAME             STATUS   ROLES                  AGE   VERSION
vms201.rhce.cc   Ready    control-plane,master   11d   v1.21.0
vms202.rhce.cc   Ready    <none>                 11d   v1.21.0
vms203.rhce.cc   Ready    <none>                 11d   v1.21.0

步骤10:创建jenkins任务,构建触发器

构建触发器的目的是让gitlab中代码修改后能够触发jenkins完成镜像构建。点击主页的新建任务:
在这里插入图片描述
输入任务名称,选择构建一个自由风格的软件项目。点击确定后,选择构建触发器:
在这里插入图片描述
然后记录触发器的URL:
JENKINS_URL/job/test_task/build?token=TOKEN_NAME,替换为自己的URL:http://192.168.0.166:8080/job/test_task/build?token=prin123;后续需要在gitlab中应用。

步骤11:定义jenkins执行的任务
选择增加构建步骤,这里记为步骤1
在这里插入图片描述
执行shell命令,从gitlab上获取克隆的代码:
在这里插入图片描述
其中,shell脚本时进入jenkins的home目录,然后删除掉原来clone的文件,然后重新克隆。克隆的地址可以在gitlab的项目中获取:
在这里插入图片描述
设置完成后,点击添加构建步骤,这记为步骤2,目的是构建镜像并推送到镜像仓库,点击build/Publish docker image,然后按照下面的图示填写:
在这里插入图片描述
完成后,继续添加构建步骤,这里记为步骤3,选择shell,这个步骤的目的是部署应用到k8s:
在这里插入图片描述
shell脚本的含义是,使用登陆文件kc1,然后替换掉deployment/wev1的镜像为自己构建的新镜像,命令空间为net。完成后选择保存。

为了配合实验,我们需要到k8s的master上创建对应的ns、deployment和服务:

[root@vms201 cicd]# kubectl create namespace net
namespace/net created
[root@vms201 cicd]# kubens net
Context "kubernetes-admin@kubernetes" modified.
Active namespace is "net".

创建对应命名空间并切换后,部署deployment,yaml文件为:

[root@vms201 cicd]# cat web1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: web1
  name: web1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web1
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: web1
    spec:
      containers:
      - image: nginx
        name: nginx
        imagePullPolicy: IfNotPresent
        resources: {}
status: {}

通过yaml文件部署3个nginx的pod:

[root@vms201 cicd]# kubectl apply -f web1.yaml
deployment.apps/web1 created
[root@vms201 cicd]# kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
web1-5bfb6d8dcc-5g9mt   1/1     Running   0          22s
web1-5bfb6d8dcc-fgqvn   1/1     Running   0          22s
web1-5bfb6d8dcc-glv5k   1/1     Running   0          22s

创建对应的服务:

[root@vms201 cicd]# kubectl expose --name=svc1 deployment web1 --port=80 --type=NodePort
service/svc1 exposed
[root@vms201 cicd]# kubectl get svc
NAME   TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
svc1   NodePort   10.105.213.119   <none>        80:32221/TCP   5s

现在可以在物理机上访问k8s集群内任意IP地址的32221端口,查看nginx应用:
在这里插入图片描述
步骤12:设置Gitlab触发jenkins
点击admin area:
在这里插入图片描述
修改outbround request配置:允许jenkins连接
在这里插入图片描述
返回自己的项目中,点击webhook,添加之前得到的jenkins的url。完成后点击添加webhook。
在这里插入图片描述
测试webhook是否成功:
在这里插入图片描述
可以看到如下的提示:说明webhook部署成功。
在这里插入图片描述
完成了这一步后,整个环境就部署完成。

七、最终测试

步骤1:在centos8上,创建一个nginx的dockerfile

[root@localhost test_project]# cat Dockerfile
FROM docker.io/nginx
MAINTAINER Prin
ADD index.html /usr/share/nginx/html/
EXPOSE 80
CMD ["nginx","-g","daemon off;"]

其中,此镜像由nginx基础镜像来构建,并且替换了index.html主页到容器内。

index.html文件如下:

[root@localhost test_project]# cat index.html
Hello World!!!! K8s CICD Test!

步骤2:将2个文件推送到到Gitlab中

[root@localhost test_project]# git add .
[root@localhost test_project]# git commit -m "test"
[master 9ed8b7f] test
 2 files changed, 6 insertions(+)
 create mode 100644 Dockerfile
 create mode 100644 index.html
[root@localhost test_project]# git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 2 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 449 bytes | 449.00 KiB/s, done.
Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
To ssh://192.168.0.166:222/root/test_project.git
   12fae63..9ed8b7f  master -> master

步骤3:查看整体效果

在gitlab上查看时是否推送成功:
在这里插入图片描述
然后再jenkins上查看构建记录:
在这里插入图片描述
查看控制台输出:
在这里插入图片描述
以下是控制台输出的内容:分别记录了再gitlab中克隆代码、构建镜像、推送镜像和部署应用的工程。
在这里插入图片描述
我们可以在游览器上重新访问k8s集群里的nginx,查看主页是否被替换:
在这里插入图片描述
可以看到,主页被替换,整体部署成功!!!

创造不易,如果觉得写的不错,请点个赞吧!!!

参考资料:
《老段CKA课程》
k8s+Jenkins+GitLab-自动化部署asp.net core项目:<https://developer.aliyun.com/article/686260>

热门文章

暂无图片
编程学习 ·

C语言二分查找详解

二分查找是一种知名度很高的查找算法&#xff0c;在对有序数列进行查找时效率远高于传统的顺序查找。 下面这张动图对比了二者的效率差距。 二分查找的基本思想就是通过把目标数和当前数列的中间数进行比较&#xff0c;从而确定目标数是在中间数的左边还是右边&#xff0c;将查…
暂无图片
编程学习 ·

GMX 命令分类列表

建模和计算操作命令&#xff1a; 1.1 . 创建拓扑与坐标文件 gmx editconf - 编辑模拟盒子以及写入子组(subgroups) gmx protonate - 结构质子化 gmx x2top - 根据坐标生成原始拓扑文件 gmx solvate - 体系溶剂化 gmx insert-molecules - 将分子插入已有空位 gmx genconf - 增加…
暂无图片
编程学习 ·

一文高效回顾研究生课程《数值分析》重点

数值分析这门课的本质就是用离散的已知点去估计整体&#xff0c;就是由黑盒子产生的结果去估计这个黑盒子。在数学里这个黑盒子就是一个函数嘛&#xff0c;这门课会介绍许多方法去利用离散点最大化地逼近这个函数&#xff0c;甚至它的导数、积分&#xff0c;甚至微分方程的解。…
暂无图片
编程学习 ·

在职阿里5年,一个28岁女软测工程师的心声

简单的先说一下&#xff0c;坐标杭州&#xff0c;14届本科毕业&#xff0c;算上年前在阿里巴巴的面试&#xff0c;一共有面试了有6家公司&#xff08;因为不想请假&#xff0c;因此只是每个晚上去其他公司面试&#xff0c;所以面试的公司比较少&#xff09; ​ 编辑切换为居中…
暂无图片
编程学习 ·

字符串左旋c语言

目录 题目&#xff1a; 解题思路&#xff1a; 第一步&#xff1a; 第二步&#xff1a; 第三步&#xff1a; 总代码&#xff1a; 题目&#xff1a; 实现一个函数&#xff0c;可以左旋字符串中的k个字符。 例如&#xff1a; ABCD左旋一个字符得到BCDA ABCD左旋两个字符…
暂无图片
编程学习 ·

设计模式--观察者模式笔记

模式的定义与特点 观察者&#xff08;Observer&#xff09;模式的定义&#xff1a;指多个对象间存在一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式&#xf…
暂无图片
编程学习 ·

睡觉突然身体动不了,什么是睡眠痽痪症

很多朋友可能有这样的体验&#xff0c;睡觉过程中突然意识清醒&#xff0c;身体却动弹不了。这时候感觉非常恐怖&#xff0c;希望旁边有一个人推自己一下。阳光以前也经常会碰到这样的情况&#xff0c;一年有一百多次&#xff0c;那时候很害怕晚上到来&#xff0c;睡觉了就会出…
暂无图片
编程学习 ·

深入理解C++智能指针——浅析MSVC源码

文章目录unique_ptrshared_ptr 与 weak_ptrstd::bad_weak_ptr 异常std::enable_shared_from_thisunique_ptr unique_ptr 是一个只移型别&#xff08;move-only type&#xff0c;只移型别还有std::mutex等&#xff09;。 结合一下工厂模式&#xff0c;看看其基本用法&#xff…
暂无图片
编程学习 ·

@TableField(exist = false)

TableField(exist false) //申明此字段不在数据库存在&#xff0c;但代码中需要用到它&#xff0c;通知Mybatis-plus在做写库操作是忽略它。,.
暂无图片
编程学习 ·

Java Web day15

第十二章文件上传和下载 一、如何实现文件上传 要实现Web开发中的文件上传功能&#xff0c;通常需要完成两步操作&#xff1a;一.是在Web页面中添加上传输入项&#xff1b;二是在Servlet中读取上传文件的数据&#xff0c;并保存到本地硬盘中。 需要使用一个Apache组织提供一个…
暂无图片
编程学习 ·

【51nod 2478】【单调栈】【前缀和】小b接水

小b接水题目解题思路Code51nod 2478 小b接水 题目 输入样例 12 0 1 0 2 1 0 1 3 2 1 2 1输出样例 6解题思路 可以发现最后能拦住水的都是向两边递减高度&#xff08;&#xff1f;&#xff09; 不管两个高积木之间的的积木是怎样乱七八糟的高度&#xff0c;最后能用来装水的…
暂无图片
编程学习 ·

花了大半天写了一个UVC扩展单元调试工具

基于DIRECTSHOW 实现的&#xff0c;用的是MFC VS2019. 详见&#xff1a;http://www.usbzh.com/article/detail-761.html 获取方法 加QQ群:952873936&#xff0c;然后在群文件\USB调试工具&测试软件\UVCXU-V1.0(UVC扩展单元调试工具-USB中文网官方版).exe USB中文网 USB中文…
暂无图片
编程学习 ·

贪心(一):区间问题、Huffman树

区间问题 例题一&#xff1a;区间选点 给定 N 个闭区间 [ai,bi]请你在数轴上选择尽量少的点&#xff0c;使得每个区间内至少包含一个选出的点。 输出选择的点的最小数量。 位于区间端点上的点也算作区间内。 输入格式 第一行包含整数 N&#xff0c;表示区间数。 接下来 …
暂无图片
编程学习 ·

C语言练习实例——费氏数列

目录 题目 解法 输出结果 题目 Fibonacci为1200年代的欧洲数学家&#xff0c;在他的着作中曾经提到&#xff1a;「若有一只免子每个月生一只小免子&#xff0c;一个月后小免子也开始生产。起初只有一只免子&#xff0c;一个月后就有两只免子&#xff0c;二个月后有三只免子…
暂无图片
编程学习 ·

Android开发(2): Android 资源

个人笔记整理 Android 资源 Android中的资源&#xff0c;一般分为两类&#xff1a; 系统内置资源&#xff1a;Android SDK中所提供的已经定义好的资源&#xff0c;用户可以直接拿来使用。 用户自定义资源&#xff1a;用户自己定义或引入的&#xff0c;只适用于当前应用的资源…
暂无图片
编程学习 ·

零基础如何在短时间内拿到算法offer

​算法工程师是利用算法处理事物的职业 算法&#xff08;Algorithm&#xff09;是一系列解决问题的清晰指令&#xff0c;也就是说&#xff0c;能够对一定规范的输入&#xff0c;在有限时间内获得所要求的输出。 如果一个算法有缺陷&#xff0c;或不适合于某个问题&#xff0c;执…
暂无图片
编程学习 ·

人工智能:知识图谱实战总结

人工智能python&#xff0c;NLP&#xff0c;知识图谱&#xff0c;机器学习&#xff0c;深度学习人工智能&#xff1a;知识图谱实战前言一、实体建模工具Protegepython&#xff0c;NLP&#xff0c;知识图谱&#xff0c;机器学习&#xff0c;深度学习 人工智能&#xff1a;知识图…
暂无图片
编程学习 ·

【无标题】

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…