devops学习 1-框架搭建
本文最后更新于 309 天前,其中的信息可能已经有所发展或是发生改变。

BV1X1EjzhE8D(溯源是马士兵学院的课)(BV1Qq4y1z7DA)

1. devops介绍

  • 适用生产环境: 软件开发
  • 背景引入: 软件开发需要由开发团队运维团队一起各司其职协同开发。这两个团队的目标大相径庭,为了减少沟通成本,提高效率,因此引入了devops

2. 运行周期

中间那个logo是jenkins。他是一个devops中很重要的部分

3.实操

1. 配置docker

虚拟机配置:

  • centos stream 10
  • 命名:master1
  • 内存:最少4G
  • IP: 10.10.10.11/24
1. 检查网络状态(仅用于本地实验情况)
1. 检查网卡配置是否正确

路径:/etc/sysconfig/network-scripts/
如编辑后记得重启网卡

2. 检查是否能联通外网

ping 一个常见的网站即可,如baidu
如果能,就表示没什么问题。

2. 设置selinux状态(生产环境慎)
[root@localhost yum.repos.d]# sudo setenforce 0
[root@localhost yum.repos.d]# sudo sed -i 's/SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config

4. 安装常用的工具
[root@localhost gitlab_docker]# dnf -y install wget vim curl nmap-ncat tcpdump jq chrony tree man\* git

3.安装docker
背景 BV13GmDY9EtV

早期生产环境的部署是直接把exe拖进linux进行手动或自动化的启停来管理的,后来人们发现这有许多弊端:

同个环境不同版本的软件所需要的环境,插件可能各不相同,当遇到升级之类的操作时需要重新配置环境,这还是在只部署了一个软件的前提下。事实上不同软件可能都会运行到linux上,这些不同的插件环境还可能导致出现兼容性错误。

为了解决这个弊端,大家开始想办法。当时虚拟机技术成熟,大家有过把软件放在虚拟机上代理的方法。但是这种方式有以下缺点:1. 镜像源太大(下一个镜像源包括很多环境);2.启关笨重(要boot啊这一类的);3.性能损耗

而docker就是解决了这些东西

1. 下载docker自带的脚本

curl -fsSL https://get.docker.com -o install-docker.sh
sudo sh install-docker.sh

2. 替换清华源

sed -i 's+https://download.docker.com+https://mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo

3. 设置启动
[root@localhost yum.repos.d]# sudo systemctl start docker
[root@localhost yum.repos.d]# sudo systemctl enable --now docker
Created symlink '/etc/systemd/system/multi-user.target.wants/docker.service' → '/usr/lib/systemd/system/docker.service'.
[root@localhost yum.repos.d]#


2. code阶段-gitlab

1.检查版本+关闭防火墙
[root@localhost ~]# docker compose version
Docker Compose version v2.35.1
[root@localhost ~]# docker -v
Docker version 28.1.1, build 4eba377
[root@localhost ~]# systemctl stop firewalld.service
[root@localhost ~]#

2. 测试拉取
[root@localhost docker]#  tee /etc/docker/daemon.json <<-'EOF'
{
    "registry-mirrors": [
        "https://docker.m.daocloud.io",
        "https://dockerproxy.com",
        "https://docker.nju.edu.cn",
        "https://docker.mirrors.ustc.edu.cn"
    ]
}
EOF
{
    "registry-mirrors": [
        "https://docker.m.daocloud.io",
        "https://dockerproxy.com",
        "https://docker.nju.edu.cn",
        "https://docker.mirrors.ustc.edu.cn"
    ]
}

[root@localhost docker]# systemctl daemon-reload
[root@localhost docker]# systemctl restart docker
[root@localhost docker]# docker run hello-world

如果弹出

e6590344b1a5: Pull complete
Digest: sha256:dd01f97f252193ae3210da231b1dca0cffab4aadb3566692d6730bf93f123a48
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:

  1. The Docker client contacted the Docker daemon.
  2. The Docker daemon pulled the “hello-world” image from the Docker Hub.
    (amd64)
  3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
  4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/

则视为成功

3.创建

在local文件夹创建路径如下:
/usr/local/docker/gitlab_docker

在gitlab_docker里创建一个名为docker-compose.yml的文件,先保存。

使用docker查找镜像后下拉。

[root@localhost docker]# docker search gitlab
Error response from daemon: Get "https://index.docker.io/v1/search?q=gitlab&n=25": dial tcp 31.13.94.23:443: connect: connection refused
[root@localhost docker]# docker search gitlab
Error response from daemon: Get "https://index.docker.io/v1/search?q=gitlab&n=25": dial tcp 157.240.10.41:443: connect: connection refused
[root@localhost docker]# docker pull gitlab/gitlab-ce:latest

由于我找不到,我跟着教程,就直接下拉了。查找了一下,pull需要指定镜像源才行

4. 配置

回到之前写的yml里,把下边的内容复制进去

# 准备docker-compose.yml文件

version: '3.1'

services:
  gitlab:
    image: 'gitlab/gitlab-ce:latest'
    container_name: gitlab
    restart: always
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://192.168.11.11:8929'#改成自己ip#
        gitlab_rails['gitlab_shell_ssh_port'] = 2224
    ports:
      - '8929:8929'
      - '2224:22'
    volumes:
      - './config:/etc/gitlab'
      - './logs:/var/log/gitlab'
      - './data:/var/opt/gitlab'

下载后,验证该镜像是否存在

[root@localhost docker]# docker images
REPOSITORY         TAG       IMAGE ID       CREATED        SIZE
gitlab/gitlab-ce   latest    e71188eb2659   5 days ago     3.63GB
hello-world        latest    74cc54e27dc4   4 months ago   10.1kB

在该位置下进行构建启动即可

[root@localhost gitlab_docker]# docker compose up -d
WARN[0000] /usr/local/docker/gitlab_docker/docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion
[+] Running 2/2
 ✔ Network gitlab_docker_default  Created                                              0.1s
 ✔ Container gitlab               Started                                              0.3s
[root@localhost gitlab_docker]#

等待一段时间过后,在浏览器输入你的ip:8929,出现这个界面为初步成功

5.ui

现在有了图形化界面后,登录名为我们的root,至于密码,需要进入到容器里边查看文件获得。

[root@localhost gitlab_docker]# docker exec -it gitlab bash
root@1e81af34b679:/# cat /etc/gitlab/initial_root_password
# WARNING: This value is valid only in the following conditions
#          1. If provided manually (either via `GITLAB_ROOT_PASSWORD` environment variable or via `gitlab_rails['initial_root_password']` setting in `gitlab.rb`, it was provided before database was seeded for the first time (usually, the first reconfigure run).
#          2. Password hasn't been changed manually, either via UI or via command line.
#
#          If the password shown here doesn't work, you must reset the admin password following https://docs.gitlab.com/ee/security/reset_user_password.html#reset-your-root-password.

Password: /5GEBoVVEjJK6Kcal5O5UzIN/UxBLdK8ocODC5HLKkY=

# NOTE: This file will be automatically deleted in the first reconfigure run after 24 hours.
root@1e81af34b679:/#

password即是我们的密码。
之后进入页面把密码改一下(Aa123456)
这样就部署成功了!


3. build阶段-maven

1. 介绍

他是apache旗下方便管理java项目的软件。

  • 有约定俗成的目录一类,方便更好地管理。
  • 解决了一些软件依赖冲突问题

这次我下了maven3.8.8和jdk8的版本。

2. 下载

jdk8是什么,没有基础的朋友们听到肯定会突然大笑)实际上要按照maven就必须先安装jdk8,就像你要说话得先有嘴巴一样,小朋友们,明白了吗?

在百度搜索jdk8即可,链接:Java 下载 | Oracle — Java Downloads | Oracle

注意:要下tar.gz版本的

maven:https://maven.apache.org/download.cgi

3. 配置

下载后拖进ftp进行解压,可以指定目录,只要自己找到就好

[root@localhost ~]# tar -zvxf jdk-8u451-linux-x64.tar.gz -C /usr/local/
[root@localhost ~]# tar -zvxf apache-maven-3.8.8-bin.tar.gz -C /usr/local/

之后找到maven的setting.xml文件,把这两行找到对应的位置复制进去

maven默认的jdk插件式1.5,由于我安装的版本是1.8,所以需要更改。

<profile>
<id>jdk18</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>

配置私服地址(这里使用阿里云)

<mirror>
    <id>aliyunmaven</id>
    <mirrorOf>*</mirrorOf>
    <name>阿里云公共仓库</name>
    <url>https://maven.aliyun.com/repository/public</url>
</mirror>

最后的配置如下:

[root@localhost conf]# cat settings.xml
<?xml version="1.0" encoding="UTF-8"?>

<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
-->

<!--
 | This is the configuration file for Maven. It can be specified at two levels:
 |
 |  1. User Level. This settings.xml file provides configuration for a single user,
 |                 and is normally provided in ${user.home}/.m2/settings.xml.
 |
 |                 NOTE: This location can be overridden with the CLI option:
 |
 |                 -s /path/to/user/settings.xml
 |
 |  2. Global Level. This settings.xml file provides configuration for all Maven
 |                 users on a machine (assuming they're all using the same Maven
 |                 installation). It's normally provided in
 |                 ${maven.conf}/settings.xml.
 |
 |                 NOTE: This location can be overridden with the CLI option:
 |
 |                 -gs /path/to/global/settings.xml
 |
 | The sections in this sample file are intended to give you a running start at
 | getting the most out of your Maven installation. Where appropriate, the default
 | values (values used when the setting is not specified) are provided.
 |
 |-->
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
  <!-- localRepository
   | The path to the local repository maven will use to store artifacts.
   |
   | Default: ${user.home}/.m2/repository
  <localRepository>/path/to/local/repo</localRepository>
  -->

  <!-- interactiveMode
   | This will determine whether maven prompts you when it needs input. If set to false,
   | maven will use a sensible default value, perhaps based on some other setting, for
   | the parameter in question.
   |
   | Default: true
  <interactiveMode>true</interactiveMode>
  -->

  <!-- offline
   | Determines whether maven should attempt to connect to the network when executing a build.
   | This will have an effect on artifact downloads, artifact deployment, and others.
   |
   | Default: false
  <offline>false</offline>
  -->

  <!-- pluginGroups
   | This is a list of additional group identifiers that will be searched when resolving plugins by their prefix, i.e.
   | when invoking a command line like "mvn prefix:goal". Maven will automatically add the group identifiers
   | "org.apache.maven.plugins" and "org.codehaus.mojo" if these are not already contained in the list.
   |-->
  <pluginGroups>
    <!-- pluginGroup
     | Specifies a further group identifier to use for plugin lookup.
    <pluginGroup>com.your.plugins</pluginGroup>
    -->
  </pluginGroups>

  <!-- proxies
   | This is a list of proxies which can be used on this machine to connect to the network.
   | Unless otherwise specified (by system property or command-line switch), the first proxy
   | specification in this list marked as active will be used.
   |-->
  <proxies>
    <!-- proxy
     | Specification for one proxy, to be used in connecting to the network.
     |
    <proxy>
      <id>optional</id>
      <active>true</active>
      <protocol>http</protocol>
      <username>proxyuser</username>
      <password>proxypass</password>
      <host>proxy.host.net</host>
      <port>80</port>
      <nonProxyHosts>local.net|some.host.com</nonProxyHosts>
    </proxy>
    -->
  </proxies>

  <!-- servers
   | This is a list of authentication profiles, keyed by the server-id used within the system.
   | Authentication profiles can be used whenever maven must make a connection to a remote server.
   |-->
  <servers>
    <!-- server
     | Specifies the authentication information to use when connecting to a particular server, identified by
     | a unique name within the system (referred to by the 'id' attribute below).
     |
     | NOTE: You should either specify username/password OR privateKey/passphrase, since these pairings are
     |       used together.
     |
    <server>
      <id>deploymentRepo</id>
      <username>repouser</username>
      <password>repopwd</password>
    </server>
    -->

    <!-- Another sample, using keys to authenticate.
    <server>
      <id>siteServer</id>
      <privateKey>/path/to/private/key</privateKey>
      <passphrase>optional; leave empty if not used.</passphrase>
    </server>
    -->
  </servers>

  <!-- mirrors
   | This is a list of mirrors to be used in downloading artifacts from remote repositories.
   |
   | It works like this: a POM may declare a repository to use in resolving certain artifacts.
   | However, this repository may have problems with heavy traffic at times, so people have mirrored
   | it to several places.
   |
   | That repository definition will have a unique id, so we can create a mirror reference for that
   | repository, to be used as an alternate download site. The mirror site will be the preferred
   | server for that repository.
   |-->
  <mirrors>
    <!-- mirror
     | Specifies a repository mirror site to use instead of a given repository. The repository that
     | this mirror serves has an ID that matches the mirrorOf element of this mirror. IDs are used
     | for inheritance and direct lookup purposes, and must be unique across the set of mirrors.
     |
    <mirror>
      <id>mirrorId</id>
      <mirrorOf>repositoryId</mirrorOf>
      <name>Human Readable Name for this Mirror.</name>
      <url>http://my.repository.com/repo/path</url>
    </mirror>
     -->

     <mirror>
    <id>aliyunmaven</id>
    <mirrorOf>*</mirrorOf>
    <name>阿里云公共仓库</name>
    <url>https://maven.aliyun.com/repository/public</url>
    </mirror>

    <mirror>
      <id>maven-default-http-blocker</id>
      <mirrorOf>external:http:*</mirrorOf>
      <name>Pseudo repository to mirror external repositories initially using HTTP.</name>
      <url>http://0.0.0.0/</url>
      <blocked>true</blocked>
    </mirror>
  </mirrors>

  <!-- profiles
   | This is a list of profiles which can be activated in a variety of ways, and which can modify
   | the build process. Profiles provided in the settings.xml are intended to provide local machine-
   | specific paths and repository locations which allow the build to work in the local environment.
   |
   | For example, if you have an integration testing plugin - like cactus - that needs to know where
   | your Tomcat instance is installed, you can provide a variable here such that the variable is
   | dereferenced during the build process to configure the cactus plugin.
   |
   | As noted above, profiles can be activated in a variety of ways. One way - the activeProfiles
   | section of this document (settings.xml) - will be discussed later. Another way essentially
   | relies on the detection of a system property, either matching a particular value for the property,
   | or merely testing its existence. Profiles can also be activated by JDK version prefix, where a
   | value of '1.4' might activate a profile when the build is executed on a JDK version of '1.4.2_07'.
   | Finally, the list of active profiles can be specified directly from the command line.
   |
   | NOTE: For profiles defined in the settings.xml, you are restricted to specifying only artifact
   |       repositories, plugin repositories, and free-form properties to be used as configuration
   |       variables for plugins in the POM.
   |
   |-->
  <profiles>
    <!-- profile
     | Specifies a set of introductions to the build process, to be activated using one or more of the
     | mechanisms described above. For inheritance purposes, and to activate profiles via <activatedProfiles/>
     | or the command line, profiles have to have an ID that is unique.
     |
     | An encouraged best practice for profile identification is to use a consistent naming convention
     | for profiles, such as 'env-dev', 'env-test', 'env-production', 'user-jdcasey', 'user-brett', etc.
     | This will make it more intuitive to understand what the set of introduced profiles is attempting
     | to accomplish, particularly when you only have a list of profile id's for debug.
     |
     | This profile example uses the JDK version to trigger activation, and provides a JDK-specific repo.
    <profile>
      <id>jdk-1.4</id>

      <activation>
        <jdk>1.4</jdk>
      </activation>

      <repositories>
        <repository>
          <id>jdk14</id>
          <name>Repository for JDK 1.4 builds</name>
          <url>http://www.myhost.com/maven/jdk14</url>
          <layout>default</layout>
          <snapshotPolicy>always</snapshotPolicy>
        </repository>
      </repositories>
    </profile>
    -->
    <profile>
    <id>jdk8</id>
    <activation>
    <activeByDefault>true</activeByDefault>
    <jdk>1.8</jdk>
    </activation>
    <properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
    </properties>
    </profile>

    <!--
     | Here is another profile, activated by the system property 'target-env' with a value of 'dev',
     | which provides a specific path to the Tomcat instance. To use this, your plugin configuration
     | might hypothetically look like:
     |
     | ...
     | <plugin>
     |   <groupId>org.myco.myplugins</groupId>
     |   <artifactId>myplugin</artifactId>
     |
     |   <configuration>
     |     <tomcatLocation>${tomcatPath}</tomcatLocation>
     |   </configuration>
     | </plugin>
     | ...
     |
     | NOTE: If you just wanted to inject this configuration whenever someone set 'target-env' to
     |       anything, you could just leave off the <value/> inside the activation-property.
     |
    <profile>
      <id>env-dev</id>

      <activation>
        <property>
          <name>target-env</name>
          <value>dev</value>
        </property>
      </activation>

      <properties>
        <tomcatPath>/path/to/tomcat/instance</tomcatPath>
      </properties>
    </profile>
    -->
  </profiles>

  <!-- activeProfiles
   | List of profiles that are active for all builds.
   |
  <activeProfiles>
    <activeProfile>alwaysActiveProfile</activeProfile>
    <activeProfile>anotherAlwaysActiveProfile</activeProfile>
  </activeProfiles>
  -->
   <activeProfiles>
   <activeProfile>jdk8</activeProfile>
   <activeProfile>anotherAlwaysActiveProfile</activeProfile>
   </activeProfiles>

</settings>


4. Jenkins

1. 介绍

它 用于持续构建和测试软件项目,从而使开发人员更容易将更改集成到项目中,并使用户更容易获得新的构建。它还允许通过大量测试和部署技术集成来持续交付软件。

2. 安装
1. 找官网

https://hub.docker.com/r/jenkins/jenkins/tags?name=2.319.1
进去里边,复制docker 的下载地址。然后复制进终端,开始下载

docker pull jenkins/jenkins

2. 构建

在cd usr/local/doc创建jenkins文件夹,里边存放yml文件。文件如下:

version: '3'

services:
  jenkins:
    image: jenkins/jenkins:laster
    container_name: jenkins
    user: "1000:1000" #这一步一定要加,不然会报错)
    ports:
      - "8080:8080"
      - "50000:50000"
    volumes:
      - ./data/:/var/jenkins_home/

然后docker compose up -d 构建,使用docker logs -f jenkins 查看是否报错。顺带一套,jenkins的初始密码也可以在里边获得。
我这里要更改data的权限让他方便写入
chmod -R 777 data
之后等待片刻,在浏览器输入你的ip+端口号即可打开。

3.配置
  1. 把maven和jdk目录都移到当时构建的jenkins的data目录下
[root@localhost jenkins]# cd ..
[root@localhost docker]# ll
总计 4
drwxr-xr-x. 5 root root   70  5月26日 20:58 gitlab_docker
drwxr-xr-x. 8 root root 4096  5月27日 00:50 jdk
drwxr-xr-x. 3 root root   44  5月27日 22:31 jenkins
drwxr-xr-x. 6 root root   99  5月27日 01:03 maven
[root@localhost docker]# mv maven/ jenkins/data/
[root@localhost docker]# mv jdk/ jenkins/data/
[root@localhost docker]# cd jenkins/
[root@localhost jenkins]# ll
总计 8
drwxrwxrwx. 15 root root 4096  5月27日 22:48 data
-rw-r--r--.  1 root root  221  5月27日 22:31 docker-compose.yml
[root@localhost jenkins]# cd data/
[root@localhost data]# ll
总计 68

drwxr-xr-x.  8 root         root         4096  5月27日 00:50 jdk

drwxr-xr-x.  6 root         root           99  5月27日 01:03 maven

4. 测试

先把之前下载好的jdk和maven挪到docker目录下的data/里,然后再ui界面添加上对应url
url是容器内的(一开始把/data下的路径隐射到了容器里的/var/jenkins_home/下。)

这里的home地址是你在为jenkins编写的yml文件中在volume一行里指定的地址。

指定之后,检查插件里的publish ssh插件是否使用。如果使用的话,我们在里边填上宿主机的ip作为测试的接收服务器,使用其在jenkins注册的账号密码作为远程连接的凭证。

远程目录你自己随便创一个就好,之后你通过jenkins push的文件都会在这个文件夹里

出现success即为自己配置成功


4. 报错

1.设置基础软件仓库时出错

备注:后面在安装时卡了,最后换了centos10的源(最小化没法用ssh,请注意)。这个问题仅作参考

解决方案1
1. 配置网络适配器

在该界面连接到以太网先

2. 使用网络源安装介质

https://mirrors.tuna.tsinghua.edu.cn/centos-stream/9-stream/BaseOS/x86_64/os

后边发现安装时间超过一个小时还没好,遂换centos10作罢

2. jenkins配置了国内镜像源但还是处于离线模式

解决方案

最新的jenkins下载部署即可,要记得对/data进行赋权

感谢大家参观我的毛坯房。

评论

  1. 博主
    10 月前
    2025-5-30 22:07:15

    WARNING

    gitlab yml配置那里,因为我今天启动一直报错,所以我今天下载了16.11.4,也改了yml中的东西
    更新如下:

    services:
     gitlab:
      image: 'gitlab/gitlab-ce:16.11.4-ce.0'
      container_name: gitlab
      restart: always
      environment:
        GITLAB_OMNIBUS_CONFIG: |
          external_url 'http://10.10.10.11:3000'
          gitlab_rails['time_zone'] = 'Asia/Shanghai'
          gitlab_rails['backup_keep_time'] = 259200 # 3 Day, 259200 seconds
      ports:
        - '3000:3000'
        - '8443:443'
        - '2224:22'
      volumes:
        - ./gitlab-data/config:/etc/gitlab
        - ./gitlab-data/logs:/var/log/gitlab
        - ./gitlab-data/data:/var/opt/gitlab
        - /etc/localtime:/etc/localtime
      logging:
        options:
          max-size: '2g'
    

    ~~ (真希望这里能支持markdown语法)~~

发送评�? 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇