►
Description
Reverse tunnel server and agent modules MR with some more info https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/merge_requests/240
A
Hi
there,
this
is
mikhail
in
this
video
I'd
like
to
talk
about
the
architecture
and
implementation
of
how
a
reverse
grpc
tunnel
works
between
the
gitlab
kubernetes
agent
and
gitlab
kubernetes
agent
server.
So
in
this
diagram,
that's
that
part
cass
gets
a
request
and
uses
an
existing
tunnel
to
the
right
agent
pod
to
send
the
request.
A
A
The
idea
is
that,
when
car
starts,
the
modules
that
expose
some
functionality
register
some
api
jrpc
endpoints
on
an
internal
jpc
server
and
or
on
the
public
api
jrpc
server,
so
the
public
api
server
is
the
one
that
can
be
accessed
by
git
lab
the
example
that
this
document
uses
is
to
get
a
list
of
ports
in
in
some
agent
and
the
internal
one
is
used
for
something
else,
and
an
example.
Here
is
a
kubernetes
api
proxy.
So
we
do
not
want
to
expose
this
api
server
internal
one.
A
So
the
idea
is,
we
expose
some
some
api
and
then
each
the
requests
that
come
to
cast
should
be
proxied
to
some
to
the
internal
jrpc
server
in
the
agent
and
then
that
server
dispatches
the
incoming
request
to
the
corresponding
agent
module.
That
is
responsible
for
you
know
the
agent
side
of
the
functionality.
A
A
We
use
the
connection
registry
to
delegate
the
handling
of
the
incoming
request
to
it
and
by
handling
we
mean
proxying,
the
requests
to
the
right
agent
via
an
incoming
tunnel.
So
here
is
the
server
side
of
the
tunnel
module
which
accepts
the
incoming
tunnel
requests
and
then
it
also
gives
them
to
the
connection
registry.
So
the
job
of
the
registry
is
to
match
incoming
requests
with
incoming
tunnels,
basically
and
proxy
the
traffic
in
both
directions.
A
So
if
there
is
no
match
in
tunnel,
then
the
incoming
connection
sits
there
and
waits
until
the
tunnel
is
registered
and
vice
versa.
If
there
is
a
tunnel,
but
then
there
is
no
incoming
request
and
the
tunnel
sits
open
and
waits,
so
both
both
incoming
connections
do
not
sit
there
forever.
Of
course
they
are,
they
can
be
interrupted
either
by
the
client,
either
an
external
party
making
their
request
to
one
of
the
jrpc
servers
or
the
tunnel.
A
It
just
has
a
max
connection
edge,
so
it
will
close
the
connection
and
re-establish
it
so,
and
the
job
of
the
counterpart
of
the
server
tunnel
model
the
agent
on
the
model
is
to
once
it
starts
getting
some
traffic
in
response
to
it.
The
established
tunnel,
it
its
job
is
to
proxy
this
traffic
to
the
internal
grpc
server
of
the
agent,
which
is
not
exposed
to
any
network.
It's
in
memory
only
and
that's
on
that
server.
We
have
this.
A
A
As
we
saw
here
so
this
server,
so
the
server
tunnel
module
uses
the
connection
which,
in
the
servers
like
the
modules,
use
the
connection
industry,
the
agent
does
not,
but
they
both
use
the
the
api,
the
jpc
api
definitions.
So
let's
look
at
that
first,
so
here
is
our
service,
so
the
agent
calls
this
method
and
it
connects
to
the
server.
A
A
Different
pods
running
in
the
same
cluster
as
as
the
same
agent.
So
if
we
introduce
a
new
api,
we
want
to
be
able
to
send
the
request
to
the
agent
to
the
pod.
That
already
supports
this
api.
If
the,
if
an
upgrade
is
in
in
progress,
so
here
we
will
use
the
we
will
list
the
supported
methods
of
this
particular
board.
Basically,
when
it
establishes
the
connection
and
then
it's
it
sits
there
and
waits
for
a
response
and
response
is
the
request,
request,
method
and
metadata.
A
A
A
A
A
So
this
is
the
definition
of
the
protocol.
Basically,
so
it's
quite
simple,
I
would
say
nothing
fancy.
Then,
let's
look
at
the.
A
A
It
should
keep
a
bunch
of
idle
connections
to
ensure
that
there
is
a
way
to
make
a
request
to
a
module,
but
it
shouldn't
be
a
fixed
number
and
should
be
a
limit
as
well,
of
course,
so
we
have
a
connection
to
cast
and
we
create
a
client
to
make
this
particular
type
of
request,
reverse
down
client
and
then
that's
that's
basically,
so
the
what
the
module
does.
Is
it
just
establishes
and
connections
at
the
moment
and
it
waits
for
them
to
stop
and
they
stop
when
the
context
is
cancelled.
A
A
So
here
is
where
we
are
making
the
out
outbound
request
and
we
send
the
descriptor
about
the
agent.
So
this
is
the
outbound
request
to
establish
the
tunnel.
Basically,
and
then
we
start,
we
start
reading
the
response
using
the
stream
visitor.
So
first
we
receive
the
request
requesting.
For
then
this
is.
A
And
here
is
the
server
is
telling
us
which
api
and
it
wants
us
to
call
and
that's
what
we
do
here.
We
have
the
connection
to
the
internal
api
server
so
to
this
internal
pass
server,
that's
what
we
do
here
establish
create
a
stream
with
this,
this
method
that
we
need
to
call
and
the
metadata
that
we
got
from
the
request,
so
both
the
method
and
metadata.
A
We
got
them
from
the
request
well
from
the
response
from
the
server
and
we
establish
the
stream,
and
then
we
tell
the
other
go
routine
to
start
say
consuming
that
that's
responses
from
that
stream,
so
that
we
can
send
them
back
then,
here,
basically,
this
is
unblocked
and
starts
working.
So
then
we
proxy
in
one
direction
and
close
that
connection
once
we
have
proxied
all
the
all
the
messages
and
then
we
proxy
the
opposite
direction.
A
A
Okay,
let's
look
at
the
server
part,
so
the
server
module
and
how
it
uses
the
connection
and
they
live
here
in
a
sibling
directory
and
we
also
have
a
factory
which
it
registers
the
end
point.
So
for
this
module
to
make
a
request,
it
registers
an
endpoint
on
the
it's.
Actually,
we
have
another
jrpc
server
here,
it's
it
it's
an
api
server
for
all
the
agents
to
connect
to,
and
that's
what
we
that's.
What
receives
the
request?
Basically
so,
and
as
a
handler
of
that
request,
we
use
the
module
itself.
A
We
ask
gitlab
for
information
on
this
agent.
If,
if
there
is
an
error,
we
return
so
no
such
agent
or
invalid
token
or
missing
token,
or
anything
like
that,
and
then
this
is
where
we.
This
is
where
we
delegate
to
the
connection
registry
to
handle
the
incoming
tunnel
connection.
So
this
part
and
the
tunnel
connection,
that's
the
method
and
this
blocks
until
either
the
context
on
the
server
turns
out
or
there
is
an
error
processing.
A
A
To
demonstrate
one
of
these,
we
can
either
look
at
a
test.
A
A
A
A
That's
the
make
request,
so
we
should
probably
show
this
first.
This
is
the
release
api,
make
request
and
receive
response,
the
stream
and
the
stream,
because
request
and
response
may
be
of
arbitrary
size.
So
it's
usual
http
staff,
headers
status
response
body
and
status
code
and
traders
and
all
the
usual
stuff.
A
A
And
the
server
is
what
I
wanted
to
show.
This
is
the
factory
for
the
server
side.
So
one
of
these
modules
it's
an
internal
we
use
here
we
use
the
jpc
server.
So
this
is
the
reverse
server.
It's
the
internal
jpg
server,
and
here
we
construct
a
jrpc
client
for
the
kubernetes
api,
which
uses
the
inter
internal
connection
to
to
this
jpc
server,
and
the
module
itself
is
the
handler
for
for
the
incoming
requests
and
let's
look
at
the
module.
A
So,
after
all,
the
checks
are
done
and
after
we
have
determined
the
agent
id
from
the
incoming
request
like
from
the
deployment
token,
for
example,
we
use
it
here
and
we
give
the
connection
register
the
incoming
connection.
Basically,
this
is
that
part.
A
Together,
yep,
you
can
have
a
look
at
how
it
works,
but
yeah.
This
is.
This
is
basically
it
registering
connections
in
in
memory
and
then
matching
them
once
incoming
tunnel
incoming
connection
came.